-- [tsx]: init.tsx
local ____lualib = require("lualib_bundle") -- 1
local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter -- 1
local __TS__ArrayEvery = ____lualib.__TS__ArrayEvery -- 1
local __TS__StringSplit = ____lualib.__TS__StringSplit -- 1
local __TS__ParseInt = ____lualib.__TS__ParseInt -- 1
local __TS__Number = ____lualib.__TS__Number -- 1
local __TS__NumberIsNaN = ____lualib.__TS__NumberIsNaN -- 1
local __TS__ArrayMap = ____lualib.__TS__ArrayMap -- 1
local __TS__MathSign = ____lualib.__TS__MathSign -- 1
local __TS__ArrayForEach = ____lualib.__TS__ArrayForEach -- 1
local __TS__NumberToFixed = ____lualib.__TS__NumberToFixed -- 1
local ____exports = {} -- 1
local getDifficultyName, MainMenu, EndingGallery, LevelSelectMenu, Game, ScaledRoot -- 1
local ____DoraX = require("DoraX") -- 3
local React = ____DoraX.React -- 3
local toNode = ____DoraX.toNode -- 3
local useRef = ____DoraX.useRef -- 3
local ____Dora = require("Dora") -- 4
local Body = ____Dora.Body -- 5
local BodyDef = ____Dora.BodyDef -- 6
local Keyboard = ____Dora.Keyboard -- 8
local Vec2 = ____Dora.Vec2 -- 11
local Rect = ____Dora.Rect -- 12
local ____print = ____Dora.print -- 13
local Color = ____Dora.Color -- 14
local Director = ____Dora.Director -- 15
local App = ____Dora.App -- 16
local Content = ____Dora.Content -- 17
local Audio = ____Dora.Audio -- 18
local View = ____Dora.View -- 20
local ANIM_CONFIG = { -- 40
	idle = { -- 41
		file = "Image/role/idle.png", -- 42
		frameWidth = 48, -- 43
		frameHeight = 32, -- 44
		frames = 10, -- 45
		duration = 1, -- 46
		loop = true, -- 47
		row = 0, -- 48
		startCol = 0 -- 49
	}, -- 49
	run = { -- 51
		file = "Image/role/move.png", -- 52
		frameWidth = 48, -- 53
		frameHeight = 32, -- 54
		frames = 10, -- 55
		duration = 1, -- 56
		loop = true, -- 57
		row = 0, -- 58
		startCol = 0 -- 59
	}, -- 59
	jump = { -- 61
		file = "Image/role/jump.png", -- 62
		frameWidth = 48, -- 63
		frameHeight = 32, -- 64
		frames = 20, -- 65
		duration = 1.7, -- 66
		loop = false, -- 67
		row = 0, -- 68
		startCol = 0 -- 69
	}, -- 69
	dash = { -- 71
		file = "Image/role/dash.png", -- 72
		frameWidth = 48, -- 73
		frameHeight = 32, -- 74
		frames = 5, -- 75
		duration = 0.5, -- 76
		loop = false, -- 77
		row = 0, -- 78
		startCol = 0 -- 79
	}, -- 79
	dead = { -- 81
		file = "Image/role/Death1.png", -- 82
		frameWidth = 48, -- 83
		frameHeight = 32, -- 84
		frames = 10, -- 85
		duration = 1, -- 86
		loop = false, -- 87
		row = 0, -- 88
		startCol = 0 -- 89
	} -- 89
} -- 89
local MAX_MOVE_SPEED = 350 -- 100
local JUMP_SPEED = 600 -- 101
local GRAVITY_Y = -1200 -- 102
local GROUND_ACCEL = 2500 -- 105
local GROUND_FRICTION = 2000 -- 106
local AIR_ACCEL = 1500 -- 109
local AIR_FRICTION = 800 -- 110
local RUN_SPEED = 1200 -- 113
local SPRINT_DURATION = 0.15 -- 114
local SPRINT_COOLDOWN = 1.5 -- 115
local DASH_WINDUP_TIME = 0.06 -- 116
local DASH_WINDUP_SLOWDOWN = 0.15 -- 117
local DASH_END_SPEED = 350 -- 118
local currentDifficulty = "normal" -- 122
local DIFFICULTY_COOLDOWNS = {easy = 0.8, normal = 1.5, hard = 2.5} -- 123
local function cycleDifficulty() -- 130
	if currentDifficulty == "easy" then -- 130
		currentDifficulty = "normal" -- 132
	elseif currentDifficulty == "normal" then -- 132
		currentDifficulty = "hard" -- 134
	else -- 134
		currentDifficulty = "easy" -- 136
	end -- 136
	SPRINT_COOLDOWN = DIFFICULTY_COOLDOWNS[currentDifficulty] -- 138
	____print(((("🎮 [难度] 切换为 " .. getDifficultyName()) .. " (冲刺冷却: ") .. tostring(SPRINT_COOLDOWN)) .. "秒)") -- 139
end -- 130
getDifficultyName = function() -- 143
	repeat -- 143
		local ____switch7 = currentDifficulty -- 143
		local ____cond7 = ____switch7 == "easy" -- 143
		if ____cond7 then -- 143
			return "简单" -- 145
		end -- 145
		____cond7 = ____cond7 or ____switch7 == "normal" -- 145
		if ____cond7 then -- 145
			return "普通" -- 146
		end -- 146
		____cond7 = ____cond7 or ____switch7 == "hard" -- 146
		if ____cond7 then -- 146
			return "困难" -- 147
		end -- 147
	until true -- 147
end -- 143
local WALL_CLIMB_SPEED = 800 -- 152
local WALL_SLIDE_SPEED = -150 -- 153
local WALL_JUMP_X = 450 -- 154
local WALL_JUMP_Y = 450 -- 155
local WALL_JUMP_CONTROL_LOCK = 0.2 -- 156
local JUMP_BUFFER_TIME = 0.1 -- 159
local COYOTE_TIME = 0.15 -- 160
local SCALE = 3 -- 163
local SHAKE_DURATION = 0.2 -- 166
local SHAKE_INTENSITY = 15 -- 167
local BRIDGE_MAX_LEN = 1000 -- 170
local BRIDGE_GROW_SPEED = 220 -- 171
local BRIDGE_THICKNESS = 6 -- 172
local BRIDGE_OFFSET_X_FRONT = 40 -- 173
local BRIDGE_OFFSET_Y = -30 -- 174
local BODY_RESOURCE_DRAIN = 1 -- 177
local CLIMB_DISABLE_AT = 0.5 -- 178
local JUMP_DECAY_START = 0.5 -- 179
local JUMP_MIN_SCALE = 0.2 -- 180
local DASH_DECAY_START = 0.5 -- 181
local DASH_MIN_SCALE = 0.3 -- 182
local TOTAL_BRIDGE_LIMIT = 1000 -- 185
local GRAVITY = Vec2(0, GRAVITY_Y) -- 188
local SOUND_FILES = { -- 193
	jump = "Audio/jump.wav", -- 194
	dash = "Audio/dash.wav", -- 195
	bridge = "Audio/bridge.wav", -- 196
	walk = "Audio/jump.wav", -- 197
	bgm_menu = "Audio/bgm_menu.mp3", -- 198
	bgm_level_1_4 = "Audio/bgm_1_4.mp3", -- 199
	bgm_level_5_7 = "Audio/bgm_5_7.mp3", -- 200
	bgm_level_8 = "Audio/bgm_8.mp3" -- 201
} -- 201
local currentBGM = "" -- 205
local currentBGMId = -1 -- 206
local function getLevelBGM(levelIndex) -- 209
	if levelIndex >= 0 and levelIndex <= 3 then -- 209
		return SOUND_FILES.bgm_level_1_4 -- 211
	elseif levelIndex >= 4 and levelIndex <= 6 then -- 211
		return SOUND_FILES.bgm_level_5_7 -- 213
	elseif levelIndex == 7 then -- 213
		return SOUND_FILES.bgm_level_8 -- 215
	end -- 215
	return SOUND_FILES.bgm_level_1_4 -- 217
end -- 209
local function playSound(soundFile, volume) -- 221
	if volume == nil then -- 221
		volume = 1 -- 221
	end -- 221
	do -- 221
		local function ____catch(e) -- 221
			____print((("⚠️ [音效] 播放失败: " .. soundFile) .. ", 错误: ") .. tostring(e)) -- 225
		end -- 225
		local ____try, ____hasReturned = pcall(function() -- 225
			Audio:play(soundFile) -- 223
		end) -- 223
		if not ____try then -- 223
			____catch(____hasReturned) -- 223
		end -- 223
	end -- 223
end -- 221
local function playBGM(soundFile, volume) -- 230
	if volume == nil then -- 230
		volume = 0.5 -- 230
	end -- 230
	if currentBGM == soundFile then -- 230
		return -- 233
	end -- 233
	do -- 233
		local function ____catch(e) -- 233
			____print((("⚠️ [音乐] 播放失败: " .. soundFile) .. ", 错误: ") .. tostring(e)) -- 248
		end -- 248
		local ____try, ____hasReturned = pcall(function() -- 248
			if currentBGMId >= 0 then -- 248
				Audio:stop(currentBGMId) -- 239
				____print("🎵 [音乐] 停止旧BGM: " .. currentBGM) -- 240
			end -- 240
			____print("🎵 [音乐] 切换BGM: " .. soundFile) -- 243
			currentBGMId = Audio:play(soundFile, true) -- 244
			currentBGM = soundFile -- 245
			____print("🎵 [音乐] 播放成功") -- 246
		end) -- 246
		if not ____try then -- 246
			____catch(____hasReturned) -- 246
		end -- 246
	end -- 246
end -- 230
local currentLevel = 0 -- 255
local playerPosition = {x = 0, y = 0} -- 256
local collectedItems = { -- 257
	false, -- 257
	false, -- 257
	false, -- 257
	false, -- 257
	false, -- 257
	false, -- 257
	false -- 257
} -- 257
local unlockedEndings = {fake = false, sacrifice = false, perfect = false} -- 258
local function getCollectedCount() -- 265
	return #__TS__ArrayFilter( -- 266
		collectedItems, -- 266
		function(____, c) return c end -- 266
	) -- 266
end -- 265
local function isAllCollected() -- 270
	return __TS__ArrayEvery( -- 271
		collectedItems, -- 271
		function(____, c) return c end -- 271
	) -- 271
end -- 270
local function getUnlockedEndingsCount() -- 275
	local count = 0 -- 276
	if unlockedEndings.fake then -- 276
		count = count + 1 -- 277
	end -- 277
	if unlockedEndings.sacrifice then -- 277
		count = count + 1 -- 278
	end -- 278
	if unlockedEndings.perfect then -- 278
		count = count + 1 -- 279
	end -- 279
	return count -- 280
end -- 275
local SAVE_FILE = "game_save.txt" -- 286
local function loadSave() -- 288
	local saveText = Content:load(SAVE_FILE) -- 289
	if saveText and #saveText > 0 then -- 289
		local parts = __TS__StringSplit(saveText, ",") -- 291
		local unlockedLevels = __TS__ParseInt(parts[1]) -- 292
		if not __TS__NumberIsNaN(__TS__Number(unlockedLevels)) then -- 292
			if #parts > 1 then -- 292
				do -- 292
					local i = 0 -- 296
					while i < 7 do -- 296
						collectedItems[i + 1] = parts[i + 1 + 1] == "1" -- 297
						i = i + 1 -- 296
					end -- 296
				end -- 296
			end -- 296
			if #parts > 8 then -- 296
				unlockedEndings.fake = parts[9] == "1" -- 302
				unlockedEndings.sacrifice = parts[10] == "1" -- 303
				unlockedEndings.perfect = parts[11] == "1" -- 304
			end -- 304
			____print(((((("📂 [存档] 加载成功: 已解锁 " .. tostring(unlockedLevels + 1)) .. " 关, 收藏品: ") .. tostring(getCollectedCount())) .. "/7, 结局: ") .. tostring(getUnlockedEndingsCount())) .. "/3") -- 306
			return unlockedLevels -- 307
		end -- 307
	end -- 307
	____print("📂 [存档] 使用默认数据: 已解锁 1 关") -- 310
	return 0 -- 311
end -- 288
local function getUnlockedLevels() -- 315
	local saveText = Content:load(SAVE_FILE) -- 316
	if saveText and #saveText > 0 then -- 316
		local parts = __TS__StringSplit(saveText, ",") -- 318
		local unlockedLevels = __TS__ParseInt(parts[1]) -- 319
		if not __TS__NumberIsNaN(__TS__Number(unlockedLevels)) then -- 319
			return unlockedLevels -- 321
		end -- 321
	end -- 321
	return 0 -- 324
end -- 315
local function saveSave(unlockedLevels) -- 327
	local collectibleData = table.concat( -- 329
		__TS__ArrayMap( -- 329
			collectedItems, -- 329
			function(____, c) return c and "1" or "0" end -- 329
		), -- 329
		"," -- 329
	) -- 329
	local endingData = ((((unlockedEndings.fake and "1" or "0") .. ",") .. (unlockedEndings.sacrifice and "1" or "0")) .. ",") .. (unlockedEndings.perfect and "1" or "0") -- 330
	local saveText = (((tostring(unlockedLevels) .. ",") .. collectibleData) .. ",") .. endingData -- 331
	local success = Content:save(SAVE_FILE, saveText) -- 332
	if success then -- 332
		____print(((((("💾 [存档] 保存成功: 已解锁 " .. tostring(unlockedLevels + 1)) .. " 关, 收藏品: ") .. tostring(getCollectedCount())) .. "/7, 结局: ") .. tostring(getUnlockedEndingsCount())) .. "/3") -- 334
	else -- 334
		____print("❌ [存档] 保存失败") -- 336
	end -- 336
end -- 327
local function saveCollectibles() -- 340
	local unlockedLevels = getUnlockedLevels() -- 341
	saveSave(unlockedLevels) -- 342
end -- 340
local function unlockNextLevel(currentLevelIndex) -- 345
	local unlockedLevels = getUnlockedLevels() -- 346
	if currentLevelIndex >= unlockedLevels then -- 346
		local newUnlockedLevels = currentLevelIndex + 1 -- 348
		saveSave(newUnlockedLevels) -- 349
		____print(("🔓 [存档] 解锁第 " .. tostring(newUnlockedLevels + 1)) .. " 关") -- 350
	end -- 350
end -- 345
local function isLevelUnlocked(levelIndex) -- 354
	local unlockedLevels = getUnlockedLevels() -- 355
	return levelIndex <= unlockedLevels -- 356
end -- 354
local function clearSave() -- 359
	do -- 359
		local i = 0 -- 361
		while i < #collectedItems do -- 361
			collectedItems[i + 1] = false -- 362
			i = i + 1 -- 361
		end -- 361
	end -- 361
	unlockedEndings.fake = false -- 365
	unlockedEndings.sacrifice = false -- 366
	unlockedEndings.perfect = false -- 367
	saveSave(0) -- 369
	____print("🗑️ [存档] 存档已清空，重置为第一关，收集品和结局进度已重置") -- 370
end -- 359
local function moveTowards(current, target, maxDelta) -- 429
	if math.abs(target - current) <= maxDelta then -- 429
		return target -- 430
	end -- 430
	return current + __TS__MathSign(target - current) * maxDelta -- 431
end -- 429
local function updateSpriteFrame(sprite, cfg, time) -- 434
	if not sprite or not sprite.texture then -- 434
		return -- 435
	end -- 435
	local tex = sprite.texture -- 437
	local texW = tex.width -- 438
	local texH = tex.height -- 439
	if texW <= 0 or texH <= 0 then -- 439
		return -- 440
	end -- 440
	local fw = cfg.frameWidth -- 442
	local fh = cfg.frameHeight -- 443
	local cols = math.floor(texW / fw) -- 444
	if cols <= 0 then -- 444
		return -- 445
	end -- 445
	local progress = time / cfg.duration -- 447
	if cfg.loop then -- 447
		progress = progress % 1 -- 449
	else -- 449
		progress = math.min(progress, 0.999) -- 451
	end -- 451
	local frameIndex = math.floor(progress * cfg.frames) -- 454
	local globalIndex = cfg.startCol + frameIndex -- 455
	local col = globalIndex % cols -- 456
	local row = cfg.row + math.floor(globalIndex / cols) -- 457
	local x = col * fw -- 459
	local y = row * fh -- 460
	sprite.textureRect = Rect(x, y, fw, fh) -- 462
	if sprite.width ~= fw then -- 462
		sprite.width = fw -- 463
	end -- 463
	if sprite.height ~= fh then -- 463
		sprite.height = fh -- 464
	end -- 464
end -- 434
local function Player(props) -- 484
	local bodyRef = useRef(nil) -- 485
	local previewRef = useRef(nil) -- 486
	local previewSpriteRef = useRef(nil) -- 487
	local previewGlowRef = useRef(nil) -- 488
	local idleRef = useRef(nil) -- 489
	local runRef = useRef(nil) -- 490
	local jumpRef = useRef(nil) -- 491
	local dashRef = useRef(nil) -- 492
	local deadRef = useRef(nil) -- 493
	local currentAnimStateRef = useRef("idle") -- 494
	local animTimerRef = useRef(0) -- 495
	local lastDirectionRef = useRef("right") -- 496
	local sprintTimerRef = useRef(0) -- 497
	local sprintCooldownRef = useRef(0) -- 498
	local sprintVelRef = useRef(Vec2(0, 0)) -- 499
	local lastSprintTimerRef = useRef(0) -- 500
	local dashWindupTimerRef = useRef(0) -- 501
	local dashWindupDirectionRef = useRef(Vec2(0, 0)) -- 502
	local lastWindupTimerRef = useRef(0) -- 503
	local coyoteTimerRef = useRef(0) -- 504
	local jumpBufferTimerRef = useRef(0) -- 505
	local groundStabilityTimerRef = useRef(0) -- 506
	local lastSpacePressedRef = useRef(false) -- 507
	local wallJumpFromDirRef = useRef(0) -- 508
	local wallJumpLockRef = useRef(0) -- 509
	local bridgeLenRef = useRef(0) -- 510
	local bodyResourceRef = useRef(1) -- 511
	local lastKPressedRef = useRef(false) -- 512
	local totalBridgeLenRef = useRef(0) -- 513
	local isDeadRef = useRef(false) -- 514
	local isWonRef = useRef(false) -- 515
	local bridgeStartXRef = useRef(0) -- 516
	local bridgeStartYRef = useRef(0) -- 517
	local hasAirDashedRef = useRef(false) -- 518
	local previewPulseRef = useRef(0) -- 519
	local walkSoundCooldownRef = useRef(0) -- 520
	local bridgesRef = useRef({}) -- 521
	local function handleUpdate(deltaTime) -- 523
		local body = bodyRef.current -- 524
		local preview = previewRef.current -- 525
		local previewSprite = previewSpriteRef.current -- 526
		local previewGlow = previewGlowRef.current -- 527
		local world = props.worldRef.current -- 528
		local sIdle = idleRef.current -- 529
		local sRun = runRef.current -- 530
		local sJump = jumpRef.current -- 531
		local sDash = dashRef.current -- 532
		local sDead = deadRef.current -- 533
		if not body or not sIdle or not sRun or not sJump or not sDash or not sDead or not world or not preview then -- 533
			return false -- 535
		end -- 535
		for ____, b in ipairs(bridgesRef.current) do -- 538
			if b.body and b.debug then -- 538
				b.debug.x = b.body.x -- 540
				b.debug.y = b.body.y -- 541
				b.debug.angle = b.body.angle -- 542
			end -- 542
		end -- 542
		if props.triggerDeathRef and props.triggerDeathRef.current and not isDeadRef.current then -- 542
			____print("💀 [Player] 被追逐尖刺击中，开始死亡动画") -- 548
			isDeadRef.current = true -- 549
			props.triggerDeathRef.current = false -- 550
		end -- 550
		if isDeadRef.current then -- 550
			body.velocityX = 0 -- 554
			body.velocityY = 0 -- 555
			if currentAnimStateRef.current ~= "dead" then -- 555
				currentAnimStateRef.current = "dead" -- 558
				animTimerRef.current = 0 -- 559
				sIdle.visible = false -- 560
				sRun.visible = false -- 561
				sJump.visible = false -- 562
				sDash.visible = false -- 563
				sDead.visible = true -- 564
			end -- 564
			animTimerRef.current = animTimerRef.current + deltaTime -- 567
			local cfg = ANIM_CONFIG.dead -- 568
			updateSpriteFrame(sDead, cfg, animTimerRef.current) -- 569
			local facingScale = (lastDirectionRef.current == "left" and -1 or 1) * SCALE -- 570
			sDead.scaleX = facingScale -- 571
			sDead.scaleY = SCALE -- 572
			if animTimerRef.current >= cfg.duration then -- 572
				____print("✅ [Player] 死亡动画播放完成") -- 575
				props:onDeath() -- 576
			end -- 576
			return false -- 579
		end -- 579
		if isWonRef.current then -- 579
			body.velocityX = 0 -- 583
			body.velocityY = 0 -- 584
			return false -- 585
		end -- 585
		local currentCanMove = props.canMoveRef.current -- 588
		if not currentCanMove then -- 588
			body.velocityX = 0 -- 590
			body.velocityY = 0 -- 591
			playerPosition.x = body.x -- 592
			playerPosition.y = body.y -- 593
			if currentAnimStateRef.current ~= "idle" then -- 593
				currentAnimStateRef.current = "idle" -- 596
				animTimerRef.current = 0 -- 597
				sIdle.visible = true -- 598
				sRun.visible = false -- 599
				sJump.visible = false -- 600
				sDash.visible = false -- 601
				sDead.visible = false -- 602
			end -- 602
			animTimerRef.current = animTimerRef.current + deltaTime -- 605
			local cfg = ANIM_CONFIG.idle -- 606
			updateSpriteFrame(sIdle, cfg, animTimerRef.current) -- 607
			return false -- 609
		end -- 609
		local playerX = body.x -- 612
		local playerY = body.y -- 613
		for ____, hazard in ipairs(props.levelConfig.hazards) do -- 616
			local dx = playerX - hazard.x -- 617
			local dy = playerY - hazard.y -- 618
			local distance = math.sqrt(dx * dx + dy * dy) -- 619
			if distance < 60 then -- 619
				if not isDeadRef.current then -- 619
					____print("💀 [Player] 触碰危险区，开始死亡动画") -- 623
					isDeadRef.current = true -- 624
				end -- 624
				return false -- 626
			end -- 626
		end -- 626
		local goal = props.levelConfig.goal -- 631
		local gdx = playerX - goal.x -- 632
		local gdy = playerY - goal.y -- 633
		local gDistance = math.sqrt(gdx * gdx + gdy * gdy) -- 634
		if gDistance < 60 then -- 634
			if not isWonRef.current and not isDeadRef.current then -- 634
				____print("🎉 [Player] 到达终点") -- 638
				isWonRef.current = true -- 639
				props:onGoal() -- 640
			end -- 640
			return false -- 642
		end -- 642
		local secretGoal = props.levelConfig.secretGoal -- 646
		if secretGoal and props.onSecretGoal then -- 646
			local sdx = playerX - secretGoal.x -- 648
			local sdy = playerY - secretGoal.y -- 649
			local sDistance = math.sqrt(sdx * sdx + sdy * sdy) -- 650
			if sDistance < 50 then -- 650
				if not isWonRef.current and not isDeadRef.current then -- 650
					____print("🌟 [Player] 发现隐藏终点！") -- 654
					isWonRef.current = true -- 655
					props:onSecretGoal() -- 656
				end -- 656
				return false -- 658
			end -- 658
		end -- 658
		if sprintCooldownRef.current > 0 then -- 658
			sprintCooldownRef.current = sprintCooldownRef.current - deltaTime -- 662
		end -- 662
		if wallJumpLockRef.current > 0 then -- 662
			wallJumpLockRef.current = wallJumpLockRef.current - deltaTime -- 663
		end -- 663
		if jumpBufferTimerRef.current > 0 then -- 663
			jumpBufferTimerRef.current = jumpBufferTimerRef.current - deltaTime -- 664
		end -- 664
		lastSprintTimerRef.current = sprintTimerRef.current -- 666
		lastWindupTimerRef.current = dashWindupTimerRef.current -- 667
		if sprintTimerRef.current > 0 then -- 667
			sprintTimerRef.current = sprintTimerRef.current - deltaTime -- 669
		end -- 669
		if dashWindupTimerRef.current > 0 then -- 669
			dashWindupTimerRef.current = dashWindupTimerRef.current - deltaTime -- 670
		end -- 670
		local isSpacePressed = Keyboard:isKeyPressed("Space") -- 672
		if Keyboard:isKeyDown("Space") then -- 672
			jumpBufferTimerRef.current = JUMP_BUFFER_TIME -- 674
		end -- 674
		local currentVx = body.velocityX -- 677
		local currentVy = body.velocityY -- 678
		if lastSpacePressedRef.current and not isSpacePressed then -- 678
			if currentVy > 0 then -- 678
				body.velocityY = currentVy * 0.5 -- 681
			end -- 681
		end -- 681
		lastSpacePressedRef.current = isSpacePressed -- 683
		local kPressed = Keyboard:isKeyPressed("K") -- 685
		local facingDir = lastDirectionRef.current == "left" and -1 or 1 -- 686
		local remainingBridgeLen = TOTAL_BRIDGE_LIMIT - totalBridgeLenRef.current -- 687
		local canCreateMoreBridge = remainingBridgeLen > 10 -- 688
		previewPulseRef.current = previewPulseRef.current + deltaTime * 4 -- 691
		if kPressed and bodyResourceRef.current > 0.01 and canCreateMoreBridge then -- 691
			if not lastKPressedRef.current then -- 691
				bridgeLenRef.current = 0 -- 695
				lastKPressedRef.current = true -- 696
				____print("🌉 [桥梁] 开始建造") -- 697
				playSound(SOUND_FILES.bridge, 0.5) -- 698
			end -- 698
			bridgeStartXRef.current = body.x + facingDir * BRIDGE_OFFSET_X_FRONT -- 702
			bridgeStartYRef.current = body.y + BRIDGE_OFFSET_Y -- 703
			local maxCurrentBridge = math.min(BRIDGE_MAX_LEN, remainingBridgeLen) -- 705
			bridgeLenRef.current = math.min(maxCurrentBridge, bridgeLenRef.current + BRIDGE_GROW_SPEED * deltaTime) -- 706
			bodyResourceRef.current = math.max(0, bodyResourceRef.current - BODY_RESOURCE_DRAIN * deltaTime * (BRIDGE_GROW_SPEED / BRIDGE_MAX_LEN)) -- 711
			if bridgeLenRef.current > 1 then -- 711
				preview.visible = true -- 718
				preview.x = bridgeStartXRef.current -- 719
				preview.y = bridgeStartYRef.current + bridgeLenRef.current * 0.5 -- 720
				preview.angle = 0 -- 721
				if previewSprite then -- 721
					previewSprite.scaleX = BRIDGE_THICKNESS -- 725
					previewSprite.scaleY = bridgeLenRef.current -- 726
					local pulseOpacity = 0.5 + math.sin(previewPulseRef.current) * 0.2 -- 729
					previewSprite.opacity = pulseOpacity -- 730
					local resourceRatio = bodyResourceRef.current -- 733
				end -- 733
				if previewGlow then -- 733
					previewGlow.scaleX = BRIDGE_THICKNESS * 1.5 -- 739
					previewGlow.scaleY = bridgeLenRef.current -- 740
					previewGlow.opacity = 0.3 + math.sin(previewPulseRef.current * 1.5) * 0.15 -- 741
				end -- 741
			end -- 741
		elseif not kPressed and lastKPressedRef.current then -- 741
			local finalLength = bridgeLenRef.current -- 745
			preview.visible = false -- 746
			if finalLength > 10 then -- 746
				local bridgeDef = BodyDef() -- 749
				bridgeDef.type = "Dynamic" -- 750
				bridgeDef.linearAcceleration = GRAVITY -- 751
				local mainLength = finalLength - BRIDGE_THICKNESS -- 753
				if mainLength > 0 then -- 753
					bridgeDef:attachPolygon( -- 755
						BRIDGE_THICKNESS, -- 755
						mainLength, -- 755
						15000, -- 755
						500, -- 755
						0 -- 755
					) -- 755
				end -- 755
				local topOffset = mainLength / 2 -- 758
				bridgeDef:attachDisk( -- 759
					Vec2(0, topOffset), -- 759
					BRIDGE_THICKNESS / 2, -- 759
					15000, -- 759
					500, -- 759
					0 -- 759
				) -- 759
				local bottomOffset = -mainLength / 2 -- 761
				bridgeDef:attachDisk( -- 762
					Vec2(0, bottomOffset), -- 762
					BRIDGE_THICKNESS / 2, -- 762
					15000, -- 762
					500, -- 762
					0 -- 762
				) -- 762
				local bridge = Body( -- 764
					bridgeDef, -- 765
					world, -- 766
					Vec2(bridgeStartXRef.current, bridgeStartYRef.current + finalLength * 0.5) -- 767
				) -- 767
				if bridge then -- 767
					____print((((("✅ [桥梁] 创建完成 - 位置: (" .. tostring(math.floor(bridgeStartXRef.current))) .. ", ") .. tostring(math.floor(bridgeStartYRef.current + finalLength * 0.5))) .. "), 长度: ") .. tostring(math.floor(finalLength))) -- 771
					bridge.fixedRotation = false -- 772
					bridge.linearDamping = 20 -- 773
					bridge.angularDamping = 20 -- 774
					bridge.angle = facingDir * 1 -- 775
					bridge.group = 2 -- 776
					local debugWorld = props.debugWorldRef.current -- 779
					if debugWorld then -- 779
						local debugBridgeDef = BodyDef() -- 781
						debugBridgeDef.type = "Static" -- 782
						if mainLength > 0 then -- 782
							debugBridgeDef:attachPolygon( -- 784
								BRIDGE_THICKNESS, -- 784
								mainLength, -- 784
								20000, -- 784
								500, -- 784
								0 -- 784
							) -- 784
						end -- 784
						debugBridgeDef:attachDisk( -- 786
							Vec2(0, mainLength / 2), -- 786
							BRIDGE_THICKNESS / 2, -- 786
							20000, -- 786
							500, -- 786
							0 -- 786
						) -- 786
						debugBridgeDef:attachDisk( -- 787
							Vec2(0, -mainLength / 2), -- 787
							BRIDGE_THICKNESS / 2, -- 787
							20000, -- 787
							500, -- 787
							0 -- 787
						) -- 787
						local debugBridge = Body( -- 789
							debugBridgeDef, -- 790
							debugWorld, -- 791
							Vec2(bridge.x, bridge.y) -- 792
						) -- 792
						if debugBridge then -- 792
							debugBridge.angle = bridge.angle -- 795
							local ____bridgesRef_current_0 = bridgesRef.current -- 795
							____bridgesRef_current_0[#____bridgesRef_current_0 + 1] = {body = bridge, debug = debugBridge, len = finalLength} -- 796
						end -- 796
					end -- 796
					totalBridgeLenRef.current = totalBridgeLenRef.current + finalLength -- 800
				end -- 800
			end -- 800
			bridgeLenRef.current = 0 -- 804
			lastKPressedRef.current = false -- 805
		elseif not kPressed then -- 805
			preview.visible = false -- 808
		end -- 808
		local usedRatio = 1 - bodyResourceRef.current -- 811
		if math.abs(currentVy) < 10 then -- 811
			groundStabilityTimerRef.current = groundStabilityTimerRef.current + deltaTime -- 814
		else -- 814
			groundStabilityTimerRef.current = 0 -- 816
		end -- 816
		local isGrounded = groundStabilityTimerRef.current > 0.05 -- 818
		if isGrounded then -- 818
			coyoteTimerRef.current = COYOTE_TIME -- 821
			wallJumpLockRef.current = 0 -- 822
			wallJumpFromDirRef.current = 0 -- 823
			hasAirDashedRef.current = false -- 824
		elseif coyoteTimerRef.current > 0 then -- 824
			coyoteTimerRef.current = coyoteTimerRef.current - deltaTime -- 826
		end -- 826
		local inputX = 0 -- 829
		if Keyboard:isKeyPressed("A") then -- 829
			inputX = -1 -- 830
		elseif Keyboard:isKeyPressed("D") then -- 830
			inputX = 1 -- 831
		end -- 831
		local onWallLeft = false -- 833
		local onWallRight = false -- 834
		if not isGrounded and currentVy < 10 then -- 834
			if inputX == -1 and math.abs(currentVx) < 10 then -- 834
				onWallLeft = true -- 836
			end -- 836
			if inputX == 1 and math.abs(currentVx) < 10 then -- 836
				onWallRight = true -- 837
			end -- 837
		end -- 837
		local climbDisabled = usedRatio >= CLIMB_DISABLE_AT -- 840
		if climbDisabled and (onWallLeft or onWallRight) then -- 840
			onWallLeft = false -- 842
			onWallRight = false -- 843
		end -- 843
		local effectiveInputX = inputX -- 846
		if wallJumpLockRef.current > 0 then -- 846
			if wallJumpFromDirRef.current == -1 and inputX == -1 or wallJumpFromDirRef.current == 1 and inputX == 1 then -- 846
				effectiveInputX = 0 -- 850
			end -- 850
		end -- 850
		local targetVx = effectiveInputX * MAX_MOVE_SPEED -- 854
		local acceleration = isGrounded and (effectiveInputX ~= 0 and GROUND_ACCEL or GROUND_FRICTION) or (effectiveInputX ~= 0 and AIR_ACCEL or AIR_FRICTION) -- 855
		local nextVx = moveTowards(currentVx, targetVx, acceleration * deltaTime) -- 859
		local canSprintCooldown = sprintCooldownRef.current <= 0 and dashWindupTimerRef.current <= 0 -- 861
		local canSprintAir = isGrounded or not hasAirDashedRef.current -- 862
		local canSprint = canSprintCooldown and canSprintAir -- 863
		if canSprint and Keyboard:isKeyDown("J") then -- 863
			local dirX = 0 -- 866
			local dirY = 0 -- 867
			if Keyboard:isKeyPressed("A") then -- 867
				dirX = -1 -- 868
			end -- 868
			if Keyboard:isKeyPressed("D") then -- 868
				dirX = 1 -- 869
			end -- 869
			if Keyboard:isKeyPressed("W") then -- 869
				dirY = 1 -- 870
			end -- 870
			if Keyboard:isKeyPressed("S") then -- 870
				dirY = -1 -- 871
			end -- 871
			if dirX == 0 and dirY > 0 then -- 871
				dirY = 0 -- 875
			end -- 875
			if dirX == 0 and dirY == 0 then -- 875
				dirX = lastDirectionRef.current == "left" and -1 or 1 -- 879
			end -- 879
			local len = math.sqrt(dirX * dirX + dirY * dirY) -- 882
			local nx = len > 0 and dirX / len or 0 -- 883
			local ny = len > 0 and dirY / len or 0 -- 884
			dashWindupDirectionRef.current = Vec2(nx, ny) -- 886
			dashWindupTimerRef.current = DASH_WINDUP_TIME -- 887
			____print("🔵 [冲刺] 开始蓄力") -- 889
			props:onDash() -- 890
		end -- 890
		local justFinishedWindup = lastWindupTimerRef.current > 0 and dashWindupTimerRef.current <= 0 -- 893
		if justFinishedWindup then -- 893
			local nx = dashWindupDirectionRef.current.x -- 895
			local ny = dashWindupDirectionRef.current.y -- 896
			local dashScale = 1 -- 898
			if usedRatio >= DASH_DECAY_START then -- 898
				local t = (usedRatio - DASH_DECAY_START) / (1 - DASH_DECAY_START) -- 900
				dashScale = math.max(DASH_MIN_SCALE, 1 - t * 0.7) -- 901
			end -- 901
			if currentLevel == 7 then -- 901
				dashScale = dashScale * 0.3 -- 904
			end -- 904
			sprintVelRef.current = Vec2(nx * RUN_SPEED * dashScale, ny * RUN_SPEED * dashScale) -- 907
			sprintTimerRef.current = SPRINT_DURATION -- 908
			sprintCooldownRef.current = SPRINT_COOLDOWN -- 909
			wallJumpLockRef.current = 0 -- 910
			if not isGrounded then -- 910
				hasAirDashedRef.current = true -- 913
				____print("⚡ [冲刺] 执行空中冲刺（已使用空中冲刺次数）") -- 914
			else -- 914
				____print("⚡ [冲刺] 执行地面冲刺") -- 916
			end -- 916
			playSound(SOUND_FILES.dash, 0.7) -- 919
			props:onDash() -- 920
		end -- 920
		local isSprinting = sprintTimerRef.current > 0 -- 923
		local isWindingUp = dashWindupTimerRef.current > 0 -- 924
		local justFinishedSprint = lastSprintTimerRef.current > 0 and sprintTimerRef.current <= 0 -- 926
		if isSprinting then -- 926
			body.velocityX = sprintVelRef.current.x -- 929
			body.velocityY = sprintVelRef.current.y -- 930
			local intentX = sprintVelRef.current.x -- 932
			local isHorizontalDash = math.abs(intentX) > 10 -- 933
			if isHorizontalDash then -- 933
				local hitRightWall = intentX > 0 and currentVx < 50 -- 936
				local hitLeftWall = intentX < 0 and currentVx > -50 -- 937
				if hitRightWall or hitLeftWall then -- 937
					body.velocityY = WALL_CLIMB_SPEED -- 939
				end -- 939
			end -- 939
		elseif justFinishedSprint then -- 939
			local sprintVel = sprintVelRef.current -- 943
			local len = math.sqrt(sprintVel.x * sprintVel.x + sprintVel.y * sprintVel.y) -- 944
			if len > 0 then -- 944
				local nx = sprintVel.x / len -- 946
				local ny = sprintVel.y / len -- 947
				body.velocityX = nx * DASH_END_SPEED -- 948
				body.velocityY = ny * DASH_END_SPEED -- 949
			else -- 949
				body.velocityX = 0 -- 951
				body.velocityY = 0 -- 952
			end -- 952
			____print("🛑 [冲刺] 冲刺结束，保持350速度") -- 954
		elseif isWindingUp then -- 954
			body.velocityX = currentVx * DASH_WINDUP_SLOWDOWN -- 956
			body.velocityY = currentVy * DASH_WINDUP_SLOWDOWN -- 957
		else -- 957
			body.velocityX = nextVx -- 959
			if (onWallLeft or onWallRight) and currentVy < 0 and currentVy < WALL_SLIDE_SPEED then -- 959
				body.velocityY = WALL_SLIDE_SPEED -- 961
			end -- 961
		end -- 961
		if jumpBufferTimerRef.current > 0 then -- 961
			local jumped = false -- 966
			local jumpScale = 1 -- 967
			if usedRatio >= JUMP_DECAY_START then -- 967
				local t = (usedRatio - JUMP_DECAY_START) / (1 - JUMP_DECAY_START) -- 970
				jumpScale = math.max(JUMP_MIN_SCALE, 1 - t) -- 971
			end -- 971
			if currentLevel == 7 then -- 971
				jumpScale = jumpScale * 0.3 -- 976
			end -- 976
			if onWallLeft then -- 976
				body.velocityX = WALL_JUMP_X -- 981
				body.velocityY = WALL_JUMP_Y * jumpScale -- 982
				jumped = true -- 983
				wallJumpFromDirRef.current = -1 -- 984
				wallJumpLockRef.current = WALL_JUMP_CONTROL_LOCK -- 985
				hasAirDashedRef.current = false -- 986
			elseif onWallRight then -- 986
				body.velocityX = -WALL_JUMP_X -- 988
				body.velocityY = WALL_JUMP_Y * jumpScale -- 989
				jumped = true -- 990
				wallJumpFromDirRef.current = 1 -- 991
				wallJumpLockRef.current = WALL_JUMP_CONTROL_LOCK -- 992
				hasAirDashedRef.current = false -- 993
			elseif coyoteTimerRef.current > 0 then -- 993
				body.velocityY = JUMP_SPEED * jumpScale -- 995
				jumped = true -- 996
			end -- 996
			if jumped then -- 996
				if not isSpacePressed then -- 996
					body.velocityY = body.velocityY * 0.5 -- 1000
				end -- 1000
				sprintTimerRef.current = 0 -- 1001
				coyoteTimerRef.current = 0 -- 1002
				jumpBufferTimerRef.current = 0 -- 1003
				groundStabilityTimerRef.current = 0 -- 1004
				playSound(SOUND_FILES.jump, 0.6) -- 1005
			end -- 1005
		end -- 1005
		if math.abs(body.velocityX) > 10 then -- 1005
			lastDirectionRef.current = body.velocityX < 0 and "left" or "right" -- 1010
		end -- 1010
		local facingScale = (lastDirectionRef.current == "left" and -1 or 1) * SCALE -- 1012
		local targetState = "idle" -- 1014
		if isSprinting or isWindingUp then -- 1014
			targetState = "dash" -- 1015
		elseif not isGrounded then -- 1015
			targetState = "jump" -- 1016
		elseif math.abs(body.velocityX) > 10 then -- 1016
			targetState = "run" -- 1017
		end -- 1017
		if currentAnimStateRef.current ~= targetState then -- 1017
			currentAnimStateRef.current = targetState -- 1020
			animTimerRef.current = 0 -- 1021
			sIdle.visible = targetState == "idle" -- 1022
			sRun.visible = targetState == "run" -- 1023
			sJump.visible = targetState == "jump" -- 1024
			sDash.visible = targetState == "dash" -- 1025
			sDead.visible = false -- 1026
		end -- 1026
		animTimerRef.current = animTimerRef.current + deltaTime -- 1029
		local cfg = ANIM_CONFIG[targetState] -- 1030
		local activeSprite = sIdle -- 1032
		if targetState == "run" then -- 1032
			activeSprite = sRun -- 1033
		elseif targetState == "jump" then -- 1033
			activeSprite = sJump -- 1034
		elseif targetState == "dash" then -- 1034
			activeSprite = sDash -- 1035
		end -- 1035
		updateSpriteFrame(activeSprite, cfg, animTimerRef.current) -- 1037
		activeSprite.scaleX = facingScale -- 1038
		activeSprite.scaleY = SCALE -- 1039
		if walkSoundCooldownRef.current > 0 then -- 1039
			walkSoundCooldownRef.current = walkSoundCooldownRef.current - deltaTime -- 1043
		end -- 1043
		if targetState == "run" and isGrounded and walkSoundCooldownRef.current <= 0 then -- 1043
			playSound(SOUND_FILES.walk, 0.3) -- 1046
			walkSoundCooldownRef.current = 0.3 -- 1047
		end -- 1047
		local newOpacity = 0.1 + bodyResourceRef.current * 0.9 -- 1053
		local isOnCooldown = sprintCooldownRef.current > 0 -- 1056
		local spriteColor = isOnCooldown and Color(33488896) or Color(4294967295) -- 1057
		sIdle.color = spriteColor -- 1060
		sRun.color = spriteColor -- 1061
		sJump.color = spriteColor -- 1062
		sDash.color = spriteColor -- 1063
		sIdle.opacity = newOpacity -- 1066
		sRun.opacity = newOpacity -- 1067
		sJump.opacity = newOpacity -- 1068
		sDash.opacity = newOpacity -- 1069
		playerPosition.x = body.x -- 1071
		playerPosition.y = body.y -- 1072
		return false -- 1074
	end -- 523
	return React.createElement( -- 1077
		React.Fragment, -- 1077
		nil, -- 1077
		React.createElement( -- 1077
			"body", -- 1077
			{ -- 1077
				ref = bodyRef, -- 1077
				type = "Dynamic", -- 1077
				x = props.x, -- 1077
				y = props.y, -- 1077
				fixedRotation = true, -- 1077
				group = 2, -- 1077
				onUpdate = handleUpdate -- 1077
			}, -- 1077
			React.createElement("sprite", { -- 1077
				ref = idleRef, -- 1077
				file = ANIM_CONFIG.idle.file, -- 1077
				scaleX = SCALE, -- 1077
				scaleY = SCALE, -- 1077
				filter = "Point", -- 1077
				visible = true, -- 1077
				anchorX = 0.5, -- 1077
				anchorY = 0.6 -- 1077
			}), -- 1077
			React.createElement("sprite", { -- 1077
				ref = runRef, -- 1077
				file = ANIM_CONFIG.run.file, -- 1077
				scaleX = SCALE, -- 1077
				scaleY = SCALE, -- 1077
				filter = "Point", -- 1077
				visible = false, -- 1077
				anchorX = 0.5, -- 1077
				anchorY = 0.6 -- 1077
			}), -- 1077
			React.createElement("sprite", { -- 1077
				ref = jumpRef, -- 1077
				file = ANIM_CONFIG.jump.file, -- 1077
				scaleX = SCALE, -- 1077
				scaleY = SCALE, -- 1077
				filter = "Point", -- 1077
				visible = false, -- 1077
				anchorX = 0.5, -- 1077
				anchorY = 0.6 -- 1077
			}), -- 1077
			React.createElement("sprite", { -- 1077
				ref = dashRef, -- 1077
				file = ANIM_CONFIG.dash.file, -- 1077
				scaleX = SCALE, -- 1077
				scaleY = SCALE, -- 1077
				filter = "Point", -- 1077
				visible = false, -- 1077
				anchorX = 0.5, -- 1077
				anchorY = 0.6 -- 1077
			}), -- 1077
			React.createElement("sprite", { -- 1077
				ref = deadRef, -- 1077
				file = ANIM_CONFIG.dead.file, -- 1077
				scaleX = SCALE, -- 1077
				scaleY = SCALE, -- 1077
				filter = "Point", -- 1077
				visible = false, -- 1077
				anchorX = 0.5, -- 1077
				anchorY = 0.6 -- 1077
			}), -- 1077
			React.createElement("rect-fixture", { -- 1077
				width = 15 * SCALE, -- 1077
				height = 25 * SCALE, -- 1077
				friction = 0, -- 1077
				restitution = 0, -- 1077
				density = 5000 -- 1077
			}) -- 1077
		), -- 1077
		React.createElement( -- 1077
			"body", -- 1077
			{ -- 1077
				ref = previewRef, -- 1077
				type = "Static", -- 1077
				x = props.x, -- 1077
				y = props.y, -- 1077
				visible = false, -- 1077
				order = 100 -- 1077
			}, -- 1077
			React.createElement("sprite", { -- 1077
				ref = previewSpriteRef, -- 1077
				file = "Image/bridge.png", -- 1077
				width = 1, -- 1077
				height = 1, -- 1077
				filter = "Point", -- 1077
				opacity = 0.7 -- 1077
			}) -- 1077
		) -- 1077
	) -- 1077
end -- 484
local function AnimatedBackground(props) -- 1119
	local spriteRef = useRef(nil) -- 1120
	local animTimerRef = useRef(0) -- 1121
	local function handleUpdate(deltaTime) -- 1123
		local sprite = spriteRef.current -- 1124
		if not sprite or not sprite.texture then -- 1124
			return false -- 1125
		end -- 1125
		animTimerRef.current = animTimerRef.current + deltaTime -- 1127
		local tex = sprite.texture -- 1130
		local texW = tex.width -- 1131
		local texH = tex.height -- 1132
		if texW <= 0 or texH <= 0 then -- 1132
			return false -- 1133
		end -- 1133
		local fw = props.frameWidth -- 1135
		local fh = props.frameHeight -- 1136
		local cols = math.floor(texW / fw) -- 1137
		if cols <= 0 then -- 1137
			return false -- 1138
		end -- 1138
		local progress = animTimerRef.current / props.duration -- 1140
		if props.loop then -- 1140
			progress = progress % 1 -- 1142
		else -- 1142
			progress = math.min(progress, 0.999) -- 1144
		end -- 1144
		local frameIndex = math.floor(progress * props.frames) -- 1147
		local col = frameIndex % cols -- 1148
		local row = math.floor(frameIndex / cols) -- 1149
		local x = col * fw -- 1151
		local y = row * fh -- 1152
		sprite.textureRect = Rect(x, y, fw, fh) -- 1154
		if sprite.width ~= props.width then -- 1154
			sprite.width = props.width -- 1156
		end -- 1156
		if sprite.height ~= props.height then -- 1156
			sprite.height = props.height -- 1157
		end -- 1157
		return false -- 1159
	end -- 1123
	return React.createElement("sprite", { -- 1162
		ref = spriteRef, -- 1162
		file = props.file, -- 1162
		width = props.width, -- 1162
		height = props.height, -- 1162
		filter = "Point", -- 1162
		onUpdate = handleUpdate -- 1162
	}) -- 1162
end -- 1119
local function Platform(props) -- 1178
	return React.createElement( -- 1178
		"body", -- 1178
		{type = "Static", x = props.x, y = props.y, group = 2}, -- 1178
		React.createElement("rect-fixture", {width = props.w, height = props.h, friction = 50, restitution = 0}), -- 1178
		React.createElement("sprite", {file = props.file or "Image/ground.png", width = props.w, height = props.h, filter = "Point"}) -- 1178
	) -- 1178
end -- 1178
local function Hazard(props) -- 1195
	return React.createElement( -- 1195
		"body", -- 1195
		{ -- 1195
			type = "Static", -- 1195
			x = props.x, -- 1195
			y = props.y, -- 1195
			order = 10, -- 1195
			group = 2 -- 1195
		}, -- 1195
		React.createElement("rect-fixture", {width = props.w, height = props.h}), -- 1195
		React.createElement("sprite", {file = props.file or "Image/hazard.png", width = props.w, height = props.h, filter = "Point"}) -- 1195
	) -- 1195
end -- 1195
local function MovingSpike(props) -- 1215
	local posXRef = useRef(props.startX) -- 1216
	local bodyRef = useRef(nil) -- 1217
	local delayTimerRef = useRef(props.delay or 0) -- 1218
	local startedRef = useRef(false) -- 1219
	local function handleUpdate(deltaTime) -- 1221
		local body = bodyRef.current -- 1222
		if not body then -- 1222
			return false -- 1223
		end -- 1223
		if delayTimerRef.current > 0 then -- 1223
			delayTimerRef.current = delayTimerRef.current - deltaTime -- 1227
			return false -- 1228
		end -- 1228
		if not startedRef.current then -- 1228
			startedRef.current = true -- 1232
			____print("⚠️ [追逐尖刺] 开始移动！") -- 1233
		end -- 1233
		posXRef.current = posXRef.current + props.speed * deltaTime -- 1237
		body.x = posXRef.current -- 1238
		local dx = playerPosition.x - posXRef.current -- 1241
		local dy = playerPosition.y - props.y -- 1242
		if math.abs(dx) < props.width / 2 + 60 and math.abs(dy) < props.height / 2 + 50 then -- 1242
			if props.onPlayerHit then -- 1242
				props:onPlayerHit() -- 1247
			end -- 1247
		end -- 1247
		if posXRef.current >= props.endX then -- 1247
			posXRef.current = props.endX -- 1253
		end -- 1253
		return false -- 1256
	end -- 1221
	return React.createElement( -- 1259
		"body", -- 1259
		{ -- 1259
			ref = bodyRef, -- 1259
			type = "Static", -- 1259
			x = props.startX, -- 1259
			y = props.y, -- 1259
			onUpdate = handleUpdate -- 1259
		}, -- 1259
		React.createElement("rect-fixture", {width = props.width, height = props.height}), -- 1259
		React.createElement("sprite", {file = props.file or "Image/hazard.png", width = props.width, height = props.height, filter = "Point"}) -- 1259
	) -- 1259
end -- 1215
local function Goal(props) -- 1272
	local rotationRef = useRef(0) -- 1273
	local nodeRef = useRef(nil) -- 1274
	local function handleUpdate(deltaTime) -- 1276
		local node = nodeRef.current -- 1277
		if not node then -- 1277
			return false -- 1278
		end -- 1278
		rotationRef.current = rotationRef.current + deltaTime * 90 -- 1279
		node.angle = rotationRef.current -- 1280
		return false -- 1281
	end -- 1276
	return React.createElement( -- 1284
		"body", -- 1284
		{type = "Static", x = props.x, y = props.y}, -- 1284
		React.createElement("rect-fixture", {width = props.size, height = props.size}), -- 1284
		React.createElement( -- 1284
			"node", -- 1284
			{ref = nodeRef, onUpdate = handleUpdate}, -- 1284
			React.createElement("sprite", {file = "Image/goal_star.png", width = props.size, height = props.size, filter = "Point"}) -- 1284
		) -- 1284
	) -- 1284
end -- 1272
local function SecretGoal(props) -- 1299
	local rotationRef = useRef(0) -- 1300
	local pulseRef = useRef(0) -- 1301
	local nodeRef = useRef(nil) -- 1302
	local glowRef = useRef(nil) -- 1303
	local function handleUpdate(deltaTime) -- 1305
		local node = nodeRef.current -- 1306
		local glow = glowRef.current -- 1307
		if not node then -- 1307
			return false -- 1308
		end -- 1308
		rotationRef.current = rotationRef.current - deltaTime * 120 -- 1310
		pulseRef.current = pulseRef.current + deltaTime * 3 -- 1311
		node.angle = rotationRef.current -- 1313
		if glow then -- 1313
			local scale = 1 + math.sin(pulseRef.current) * 0.2 -- 1316
			glow.scaleX = scale -- 1317
			glow.scaleY = scale -- 1318
			glow.opacity = 0.3 + math.sin(pulseRef.current * 2) * 0.15 -- 1319
		end -- 1319
		return false -- 1322
	end -- 1305
	return React.createElement( -- 1325
		"body", -- 1325
		{type = "Static", x = props.x, y = props.y}, -- 1325
		React.createElement("rect-fixture", {width = props.size, height = props.size}), -- 1325
		React.createElement("sprite", { -- 1325
			ref = glowRef, -- 1325
			file = "Image/goal_star.png", -- 1325
			width = props.size * 2, -- 1325
			height = props.size * 2, -- 1325
			filter = "Point", -- 1325
			opacity = 0.3 -- 1325
		}), -- 1325
		React.createElement( -- 1325
			"node", -- 1325
			{ref = nodeRef, onUpdate = handleUpdate}, -- 1325
			React.createElement("sprite", {file = "Image/goal_star.png", width = props.size, height = props.size, filter = "Point"}) -- 1325
		) -- 1325
	) -- 1325
end -- 1299
local NPC_ANIM_CONFIG = { -- 1349
	file = "Image/NPC.png", -- 1350
	frameWidth = 32, -- 1351
	frameHeight = 48, -- 1352
	frames = 7, -- 1353
	duration = 0.7, -- 1354
	loop = true -- 1355
} -- 1355
local function NPC(props) -- 1358
	local bobRef = useRef(0) -- 1359
	local nodeRef = useRef(nil) -- 1360
	local spriteRef = useRef(nil) -- 1361
	local animTimerRef = useRef(0) -- 1362
	local function handleUpdate(deltaTime) -- 1364
		local node = nodeRef.current -- 1365
		local sprite = spriteRef.current -- 1366
		if not node then -- 1366
			return false -- 1367
		end -- 1367
		bobRef.current = bobRef.current + deltaTime * 2 -- 1370
		local bobOffset = math.sin(bobRef.current) * 5 -- 1371
		node.y = bobOffset -- 1372
		if sprite and sprite.texture then -- 1372
			animTimerRef.current = animTimerRef.current + deltaTime -- 1376
			local cfg = NPC_ANIM_CONFIG -- 1377
			local tex = sprite.texture -- 1379
			local texW = tex.width -- 1380
			local texH = tex.height -- 1381
			if texW > 0 and texH > 0 then -- 1381
				local cols = math.floor(texW / cfg.frameWidth) -- 1383
				if cols > 0 then -- 1383
					local progress = animTimerRef.current / cfg.duration % 1 -- 1385
					local frameIndex = math.floor(progress * cfg.frames) -- 1386
					local col = frameIndex % cols -- 1387
					local row = math.floor(frameIndex / cols) -- 1388
					sprite.textureRect = Rect(col * cfg.frameWidth, row * cfg.frameHeight, cfg.frameWidth, cfg.frameHeight) -- 1390
				end -- 1390
			end -- 1390
		end -- 1390
		return false -- 1395
	end -- 1364
	local NPC_SCALE = 2 -- 1398
	return React.createElement( -- 1400
		"body", -- 1400
		{type = "Static", x = props.x, y = props.y}, -- 1400
		React.createElement("rect-fixture", {width = 40, height = 60, sensorOnly = true}), -- 1400
		React.createElement( -- 1400
			"node", -- 1400
			{ref = nodeRef, onUpdate = handleUpdate}, -- 1400
			React.createElement("sprite", { -- 1400
				ref = spriteRef, -- 1400
				file = NPC_ANIM_CONFIG.file, -- 1400
				scaleX = 0.45, -- 1400
				scaleY = 3, -- 1400
				filter = "Point" -- 1400
			}), -- 1400
			React.createElement( -- 1400
				"node", -- 1400
				{y = 35}, -- 1400
				React.createElement( -- 1400
					"draw-node", -- 1400
					nil, -- 1400
					React.createElement( -- 1400
						"polygon-shape", -- 1400
						{ -- 1400
							verts = { -- 1400
								Vec2(-5, 0), -- 1417
								Vec2(5, 0), -- 1418
								Vec2(0, 8) -- 1419
							}, -- 1419
							fillColor = 4294967295 -- 1419
						} -- 1419
					) -- 1419
				) -- 1419
			) -- 1419
		) -- 1419
	) -- 1419
end -- 1358
local function Collectible(props) -- 1431
	local bobRef = useRef(0) -- 1432
	local collectedRef = useRef(false) -- 1433
	local spriteRef = useRef(nil) -- 1434
	local bodyRef = useRef(nil) -- 1435
	local alreadyCollected = collectedItems[props.levelIndex + 1] -- 1438
	local function handleUpdate(deltaTime) -- 1440
		local sprite = spriteRef.current -- 1441
		local body = bodyRef.current -- 1442
		if not sprite or collectedRef.current or alreadyCollected then -- 1442
			return false -- 1443
		end -- 1443
		bobRef.current = bobRef.current + deltaTime * 3 -- 1445
		local bobOffset = math.sin(bobRef.current) * 8 -- 1447
		sprite.y = bobOffset -- 1448
		local scale = 1 + math.sin(bobRef.current * 2) * 0.1 -- 1451
		sprite.scaleX = scale -- 1452
		sprite.scaleY = scale -- 1453
		local dx = playerPosition.x - props.x -- 1456
		local dy = playerPosition.y - props.y -- 1457
		local distance = math.sqrt(dx * dx + dy * dy) -- 1458
		if distance < 50 then -- 1458
			collectedRef.current = true -- 1461
			collectedItems[props.levelIndex + 1] = true -- 1462
			____print(((("🌟 [收集品] 收集了第 " .. tostring(props.levelIndex + 1)) .. " 关的收集品！(") .. tostring(getCollectedCount())) .. "/7)") -- 1463
			if body then -- 1463
				body.visible = false -- 1467
			end -- 1467
			props:onCollect() -- 1470
			return true -- 1471
		end -- 1471
		return false -- 1474
	end -- 1440
	if alreadyCollected then -- 1440
		return nil -- 1479
	end -- 1479
	return React.createElement( -- 1482
		"body", -- 1482
		{ -- 1482
			ref = bodyRef, -- 1482
			type = "Static", -- 1482
			x = props.x, -- 1482
			y = props.y, -- 1482
			onUpdate = handleUpdate -- 1482
		}, -- 1482
		React.createElement("sprite", { -- 1482
			ref = spriteRef, -- 1482
			file = props.file, -- 1482
			width = 40, -- 1482
			height = 40, -- 1482
			filter = "Point" -- 1482
		}) -- 1482
	) -- 1482
end -- 1431
local function LevelText(props) -- 1505
	local labelRef = useRef(nil) -- 1506
	local showDistance = props.showDistance or 0 -- 1507
	local function handleUpdate(deltaTime) -- 1509
		local label = labelRef.current -- 1510
		if not label then -- 1510
			return false -- 1511
		end -- 1511
		if showDistance > 0 then -- 1511
			local dx = playerPosition.x - props.x -- 1515
			local dy = playerPosition.y - props.y -- 1516
			local distance = math.sqrt(dx * dx + dy * dy) -- 1517
			if distance < showDistance then -- 1517
				local fadeRatio = 1 - distance / showDistance -- 1521
				label.opacity = math.min(1, fadeRatio * 1.5) -- 1522
			else -- 1522
				label.opacity = 0 -- 1524
			end -- 1524
		else -- 1524
			label.opacity = 1 -- 1527
		end -- 1527
		return false -- 1530
	end -- 1509
	return React.createElement( -- 1533
		"node", -- 1533
		{x = props.x, y = props.y, onUpdate = handleUpdate}, -- 1533
		React.createElement("label", { -- 1533
			ref = labelRef, -- 1533
			fontName = "sarasa-mono-sc-regular", -- 1533
			fontSize = props.fontSize or 24, -- 1533
			text = props.text, -- 1533
			alignment = "Center", -- 1533
			opacity = showDistance > 0 and 0 or 1 -- 1533
		}) -- 1533
	) -- 1533
end -- 1505
local LEVELS = { -- 1551
	{ -- 1552
		playerStart = {x = -600, y = 50}, -- 1553
		cameraLimitX = {min = -1000, max = 1000}, -- 1554
		platforms = { -- 1555
			{ -- 1557
				x = -1920, -- 1557
				y = -400, -- 1557
				w = 1920, -- 1557
				h = 490, -- 1557
				file = "Image/ground.png" -- 1557
			}, -- 1557
			{ -- 1558
				x = 0, -- 1558
				y = -400, -- 1558
				w = 1920, -- 1558
				h = 490, -- 1558
				file = "Image/ground.png" -- 1558
			}, -- 1558
			{ -- 1560
				x = 1920, -- 1560
				y = -400, -- 1560
				w = 1920, -- 1560
				h = 490, -- 1560
				file = "Image/ground.png" -- 1560
			}, -- 1560
			{ -- 1562
				x = 390, -- 1562
				y = 50, -- 1562
				w = 300, -- 1562
				h = 700, -- 1562
				file = "Image/platform2.png" -- 1562
			}, -- 1562
			{ -- 1563
				x = 150, -- 1563
				y = 200, -- 1563
				w = 100, -- 1563
				h = 20, -- 1563
				file = "Image/platform.png" -- 1563
			}, -- 1563
			{ -- 1564
				x = 1200, -- 1564
				y = 200, -- 1564
				w = 160, -- 1564
				h = 20, -- 1564
				file = "Image/platform.png" -- 1564
			}, -- 1564
			{ -- 1565
				x = 800, -- 1565
				y = 400, -- 1565
				w = 160, -- 1565
				h = 20, -- 1565
				file = "Image/platform.png" -- 1565
			}, -- 1565
			{ -- 1566
				x = -100, -- 1566
				y = -100, -- 1566
				w = 150, -- 1566
				h = 190, -- 1566
				file = "Image/platform2.png" -- 1566
			}, -- 1566
			{ -- 1569
				x = -1900, -- 1569
				y = 225, -- 1569
				w = 220, -- 1569
				h = 1200, -- 1569
				file = "Image/Leftwall.png" -- 1569
			}, -- 1569
			{ -- 1570
				x = 1900, -- 1570
				y = 225, -- 1570
				w = 220, -- 1570
				h = 1200, -- 1570
				file = "Image/Rightwall.png" -- 1570
			} -- 1570
		}, -- 1570
		hazards = { -- 1572
			{ -- 1573
				x = -400, -- 1573
				y = -150, -- 1573
				w = 100, -- 1573
				h = 20, -- 1573
				file = "Image/trapup.png" -- 1573
			}, -- 1573
			{ -- 1574
				x = 600, -- 1574
				y = -150, -- 1574
				w = 100, -- 1574
				h = 20, -- 1574
				file = "Image/trapup.png" -- 1574
			}, -- 1574
			{ -- 1575
				x = 700, -- 1575
				y = -150, -- 1575
				w = 100, -- 1575
				h = 20, -- 1575
				file = "Image/trapup.png" -- 1575
			}, -- 1575
			{ -- 1576
				x = 800, -- 1576
				y = -150, -- 1576
				w = 100, -- 1576
				h = 20, -- 1576
				file = "Image/trapup.png" -- 1576
			}, -- 1576
			{ -- 1577
				x = 900, -- 1577
				y = -150, -- 1577
				w = 100, -- 1577
				h = 20, -- 1577
				file = "Image/trapup.png" -- 1577
			}, -- 1577
			{ -- 1578
				x = 1000, -- 1578
				y = -150, -- 1578
				w = 100, -- 1578
				h = 20, -- 1578
				file = "Image/trapup.png" -- 1578
			}, -- 1578
			{ -- 1579
				x = 2000, -- 1579
				y = -150, -- 1579
				w = 100, -- 1579
				h = 20, -- 1579
				file = "Image/trapup.png" -- 1579
			} -- 1579
		}, -- 1579
		goal = {x = 1200, y = 230, size = 40}, -- 1582
		collectible = {x = -500, y = 50, file = "Image/bluegreen1.png"}, -- 1583
		texts = { -- 1584
			{ -- 1585
				x = -600, -- 1585
				y = -50, -- 1585
				text = "A/D 移动  空格 跳跃", -- 1585
				fontSize = 20, -- 1585
				showDistance = 200 -- 1585
			}, -- 1585
			{ -- 1586
				x = -500, -- 1586
				y = 50, -- 1586
				text = "这是钥匙...", -- 1586
				fontSize = 20, -- 1586
				showDistance = 200 -- 1586
			}, -- 1586
			{ -- 1587
				x = -400, -- 1587
				y = -50, -- 1587
				text = "小心陷阱！", -- 1587
				fontSize = 20, -- 1587
				showDistance = 200 -- 1587
			}, -- 1587
			{ -- 1588
				x = -200, -- 1588
				y = -50, -- 1588
				text = "长按空格跳的更高", -- 1588
				fontSize = 20, -- 1588
				showDistance = 200 -- 1588
			}, -- 1588
			{ -- 1589
				x = 0, -- 1589
				y = 100, -- 1589
				text = "按j键冲刺，配合方向键可选择冲刺方向", -- 1589
				fontSize = 20, -- 1589
				showDistance = 250 -- 1589
			}, -- 1589
			{ -- 1590
				x = 130, -- 1590
				y = -80, -- 1590
				text = "跳起来也可以冲刺！", -- 1590
				fontSize = 20, -- 1590
				showDistance = 200 -- 1590
			}, -- 1590
			{ -- 1591
				x = 130, -- 1591
				y = -100, -- 1591
				text = "w+d+j可以斜向冲", -- 1591
				fontSize = 20, -- 1591
				showDistance = 200 -- 1591
			}, -- 1591
			{ -- 1592
				x = 150, -- 1592
				y = 300, -- 1592
				text = "试试在右边的墙上按d+空格", -- 1592
				fontSize = 20, -- 1592
				showDistance = 200 -- 1592
			}, -- 1592
			{ -- 1593
				x = 200, -- 1593
				y = 400, -- 1593
				text = "爬不上去就冲上去！", -- 1593
				fontSize = 20, -- 1593
				showDistance = 200 -- 1593
			}, -- 1593
			{ -- 1594
				x = 390, -- 1594
				y = 550, -- 1594
				text = "按k建造桥梁", -- 1594
				fontSize = 20, -- 1594
				showDistance = 200 -- 1594
			}, -- 1594
			{ -- 1595
				x = 390, -- 1595
				y = 530, -- 1595
				text = "建桥越多，你的能力就越少", -- 1595
				fontSize = 20, -- 1595
				showDistance = 200 -- 1595
			}, -- 1595
			{ -- 1596
				x = 1200, -- 1596
				y = 300, -- 1596
				text = "通往下一关", -- 1596
				fontSize = 20, -- 1596
				showDistance = 200 -- 1596
			} -- 1596
		}, -- 1596
		npc = {x = -800, y = -80}, -- 1598
		dialog = {start = { -- 1599
			{speaker = "player", name = "你", text = "终于找到你了。"}, -- 1601
			{speaker = "player", name = "你", text = "跟我走，我带你出去。"}, -- 1602
			{speaker = "npc", name = "ta", text = "你是谁......这是哪里？"}, -- 1603
			{speaker = "npc", name = "ta", text = "好冷...我想不起来..."}, -- 1604
			{speaker = "npc", name = "ta", text = "..."}, -- 1605
			{speaker = "npc", name = "ta", text = "..."} -- 1606
		}, ["end"] = {}}, -- 1606
		intro = {title = "第一章", subtitle = "沉睡的记忆"}, -- 1611
		background = { -- 1615
			file = "Image/role/BlueSky.png", -- 1616
			width = 2640, -- 1617
			height = 1490, -- 1618
			parallax = 0.3, -- 1619
			animated = true, -- 1620
			frameWidth = 792, -- 1621
			frameHeight = 447, -- 1622
			frames = 9, -- 1623
			duration = 1.8 -- 1624
		} -- 1624
	}, -- 1624
	{ -- 1628
		playerStart = {x = -800, y = 100}, -- 1629
		cameraLimitX = {min = -1000, max = 1000}, -- 1630
		platforms = { -- 1631
			{ -- 1634
				x = -1920, -- 1634
				y = -400, -- 1634
				w = 1920, -- 1634
				h = 490, -- 1634
				file = "Image/ground.png" -- 1634
			}, -- 1634
			{ -- 1635
				x = 0, -- 1635
				y = -400, -- 1635
				w = 1920, -- 1635
				h = 490, -- 1635
				file = "Image/ground.png" -- 1635
			}, -- 1635
			{ -- 1637
				x = 1920, -- 1637
				y = -400, -- 1637
				w = 1920, -- 1637
				h = 490, -- 1637
				file = "Image/ground.png" -- 1637
			}, -- 1637
			{ -- 1641
				x = -600, -- 1641
				y = -100, -- 1641
				w = 200, -- 1641
				h = 200, -- 1641
				file = "Image/platform2.png" -- 1641
			}, -- 1641
			{ -- 1642
				x = 200, -- 1642
				y = -100, -- 1642
				w = 200, -- 1642
				h = 400, -- 1642
				file = "Image/platform2.png" -- 1642
			}, -- 1642
			{ -- 1643
				x = -300, -- 1643
				y = 400, -- 1643
				w = 100, -- 1643
				h = 20, -- 1643
				file = "Image/platform.png" -- 1643
			}, -- 1643
			{ -- 1644
				x = 400, -- 1644
				y = 100, -- 1644
				w = 200, -- 1644
				h = 800, -- 1644
				file = "Image/platform2.png" -- 1644
			}, -- 1644
			{ -- 1645
				x = 600, -- 1645
				y = -100, -- 1645
				w = 200, -- 1645
				h = 200, -- 1645
				file = "Image/platform2.png" -- 1645
			}, -- 1645
			{ -- 1646
				x = 1040, -- 1646
				y = 380, -- 1646
				w = 100, -- 1646
				h = 20, -- 1646
				file = "Image/platform.png" -- 1646
			}, -- 1646
			{ -- 1652
				x = -1900, -- 1652
				y = 225, -- 1652
				w = 220, -- 1652
				h = 1200, -- 1652
				file = "Image/Leftwall.png" -- 1652
			}, -- 1652
			{ -- 1653
				x = 1900, -- 1653
				y = 225, -- 1653
				w = 220, -- 1653
				h = 1200, -- 1653
				file = "Image/Rightwall.png" -- 1653
			} -- 1653
		}, -- 1653
		hazards = { -- 1657
			{ -- 1658
				x = -450, -- 1658
				y = -150, -- 1658
				w = 100, -- 1658
				h = 20, -- 1658
				file = "Image/trapup.png" -- 1658
			}, -- 1658
			{ -- 1659
				x = -350, -- 1659
				y = -150, -- 1659
				w = 100, -- 1659
				h = 20, -- 1659
				file = "Image/trapup.png" -- 1659
			}, -- 1659
			{ -- 1660
				x = -250, -- 1660
				y = -150, -- 1660
				w = 100, -- 1660
				h = 20, -- 1660
				file = "Image/trapup.png" -- 1660
			}, -- 1660
			{ -- 1661
				x = -150, -- 1661
				y = -150, -- 1661
				w = 100, -- 1661
				h = 20, -- 1661
				file = "Image/trapup.png" -- 1661
			}, -- 1661
			{ -- 1662
				x = -50, -- 1662
				y = -150, -- 1662
				w = 100, -- 1662
				h = 20, -- 1662
				file = "Image/trapup.png" -- 1662
			}, -- 1662
			{ -- 1663
				x = 50, -- 1663
				y = -150, -- 1663
				w = 100, -- 1663
				h = 20, -- 1663
				file = "Image/trapup.png" -- 1663
			}, -- 1663
			{ -- 1665
				x = 1700, -- 1665
				y = -150, -- 1665
				w = 100, -- 1665
				h = 20, -- 1665
				file = "Image/trapup.png" -- 1665
			}, -- 1665
			{ -- 1666
				x = 1600, -- 1666
				y = -150, -- 1666
				w = 100, -- 1666
				h = 20, -- 1666
				file = "Image/trapup.png" -- 1666
			}, -- 1666
			{ -- 1667
				x = 1500, -- 1667
				y = -150, -- 1667
				w = 100, -- 1667
				h = 20, -- 1667
				file = "Image/trapup.png" -- 1667
			}, -- 1667
			{ -- 1668
				x = 1400, -- 1668
				y = -150, -- 1668
				w = 100, -- 1668
				h = 20, -- 1668
				file = "Image/trapup.png" -- 1668
			}, -- 1668
			{ -- 1669
				x = 1300, -- 1669
				y = -150, -- 1669
				w = 100, -- 1669
				h = 20, -- 1669
				file = "Image/trapup.png" -- 1669
			}, -- 1669
			{ -- 1671
				x = 1200, -- 1671
				y = -150, -- 1671
				w = 100, -- 1671
				h = 20, -- 1671
				file = "Image/trapup.png" -- 1671
			}, -- 1671
			{ -- 1672
				x = 1100, -- 1672
				y = -150, -- 1672
				w = 100, -- 1672
				h = 20, -- 1672
				file = "Image/trapup.png" -- 1672
			}, -- 1672
			{ -- 1673
				x = 1000, -- 1673
				y = -150, -- 1673
				w = 100, -- 1673
				h = 20, -- 1673
				file = "Image/trapup.png" -- 1673
			}, -- 1673
			{ -- 1674
				x = 900, -- 1674
				y = -150, -- 1674
				w = 100, -- 1674
				h = 20, -- 1674
				file = "Image/trapup.png" -- 1674
			}, -- 1674
			{ -- 1675
				x = 800, -- 1675
				y = -150, -- 1675
				w = 100, -- 1675
				h = 20, -- 1675
				file = "Image/trapup.png" -- 1675
			}, -- 1675
			{ -- 1679
				x = 1040, -- 1679
				y = 400, -- 1679
				w = 40, -- 1679
				h = 20, -- 1679
				file = "Image/trapup.png" -- 1679
			} -- 1679
		}, -- 1679
		goal = {x = 1600, y = 100, size = 40}, -- 1682
		collectible = {x = -300, y = 450, file = "Image/orange1.png"}, -- 1683
		npc = {x = -1000, y = -80}, -- 1684
		dialog = {start = { -- 1685
			{speaker = "npc", name = "ta", text = "你...好熟悉的感觉..."}, -- 1687
			{speaker = "npc", name = "ta", text = "有个声音...滴、滴、滴...一直响着..."}, -- 1688
			{speaker = "player", name = "你", text = "你还记得那个声音？"}, -- 1689
			{speaker = "npc", name = "ta", text = "很规律...像心跳...在白色的地方..."}, -- 1690
			{speaker = "player", name = "你", text = "那是你还在的证明。"}, -- 1691
			{speaker = "npc", name = "ta", text = "我还在吗？"}, -- 1692
			{speaker = "player", name = "你", text = "在。所以我能找到你。"}, -- 1693
			{speaker = "npc", name = "ta", text = "..."}, -- 1694
			{speaker = "npc", name = " ta", text = "..."} -- 1695
		}, ["end"] = {}}, -- 1695
		intro = {title = "第二章", subtitle = "遗失的声音"}, -- 1699
		background = { -- 1703
			file = "Image/role/BlueSky.png", -- 1704
			width = 2640, -- 1705
			height = 1490, -- 1706
			parallax = 0.3, -- 1707
			animated = true, -- 1708
			frameWidth = 792, -- 1709
			frameHeight = 447, -- 1710
			frames = 9, -- 1711
			duration = 1.8 -- 1712
		} -- 1712
	}, -- 1712
	{ -- 1716
		playerStart = {x = -1100, y = 150}, -- 1717
		cameraLimitX = {min = -1000, max = 1000}, -- 1718
		platforms = { -- 1719
			{ -- 1721
				x = -1920, -- 1721
				y = -400, -- 1721
				w = 1920, -- 1721
				h = 490, -- 1721
				file = "Image/ground.png" -- 1721
			}, -- 1721
			{ -- 1722
				x = 0, -- 1722
				y = -400, -- 1722
				w = 1920, -- 1722
				h = 490, -- 1722
				file = "Image/ground.png" -- 1722
			}, -- 1722
			{ -- 1724
				x = 1920, -- 1724
				y = -400, -- 1724
				w = 1920, -- 1724
				h = 490, -- 1724
				file = "Image/ground.png" -- 1724
			}, -- 1724
			{ -- 1728
				x = 200, -- 1728
				y = -50, -- 1728
				w = 200, -- 1728
				h = 300, -- 1728
				file = "Image/platform2.png" -- 1728
			}, -- 1728
			{ -- 1730
				x = -600, -- 1730
				y = 400, -- 1730
				w = 100, -- 1730
				h = 20, -- 1730
				file = "Image/platform.png" -- 1730
			}, -- 1730
			{ -- 1731
				x = -1000, -- 1731
				y = 350, -- 1731
				w = 100, -- 1731
				h = 20, -- 1731
				file = "Image/platform.png" -- 1731
			}, -- 1731
			{ -- 1733
				x = 600, -- 1733
				y = -20, -- 1733
				w = 150, -- 1733
				h = 350, -- 1733
				file = "Image/platform2.png" -- 1733
			}, -- 1733
			{ -- 1734
				x = 600, -- 1734
				y = 500, -- 1734
				w = 150, -- 1734
				h = 300, -- 1734
				file = "Image/platform1.png" -- 1734
			}, -- 1734
			{ -- 1736
				x = 30, -- 1736
				y = -50, -- 1736
				w = 150, -- 1736
				h = 300, -- 1736
				file = "Image/platform2.png" -- 1736
			}, -- 1736
			{ -- 1737
				x = 30, -- 1737
				y = 350, -- 1737
				w = 150, -- 1737
				h = 300, -- 1737
				file = "Image/platform1.png" -- 1737
			}, -- 1737
			{ -- 1739
				x = 1000, -- 1739
				y = -50, -- 1739
				w = 400, -- 1739
				h = 300, -- 1739
				file = "Image/platform2.png" -- 1739
			}, -- 1739
			{ -- 1747
				x = -1900, -- 1747
				y = 225, -- 1747
				w = 220, -- 1747
				h = 1200, -- 1747
				file = "Image/Leftwall.png" -- 1747
			}, -- 1747
			{ -- 1748
				x = 1900, -- 1748
				y = 225, -- 1748
				w = 220, -- 1748
				h = 1200, -- 1748
				file = "Image/Rightwall.png" -- 1748
			} -- 1748
		}, -- 1748
		hazards = { -- 1751
			{ -- 1752
				x = -1000, -- 1752
				y = -150, -- 1752
				w = 100, -- 1752
				h = 20, -- 1752
				file = "Image/trapup.png" -- 1752
			}, -- 1752
			{ -- 1753
				x = -800, -- 1753
				y = -150, -- 1753
				w = 100, -- 1753
				h = 20, -- 1753
				file = "Image/trapup.png" -- 1753
			}, -- 1753
			{ -- 1754
				x = -600, -- 1754
				y = -150, -- 1754
				w = 100, -- 1754
				h = 20, -- 1754
				file = "Image/trapup.png" -- 1754
			}, -- 1754
			{ -- 1755
				x = 600, -- 1755
				y = 160, -- 1755
				w = 150, -- 1755
				h = 20, -- 1755
				file = "Image/trapup.png" -- 1755
			}, -- 1755
			{ -- 1756
				x = 600, -- 1756
				y = 340, -- 1756
				w = 150, -- 1756
				h = 20, -- 1756
				file = "Image/trapdown.png" -- 1756
			}, -- 1756
			{ -- 1757
				x = 600, -- 1757
				y = 660, -- 1757
				w = 150, -- 1757
				h = 20, -- 1757
				file = "Image/trapup.png" -- 1757
			} -- 1757
		}, -- 1757
		goal = {x = -1500, y = 550, size = 40}, -- 1759
		collectible = {x = 1000, y = 150, file = "Image/blue1.png"}, -- 1760
		npc = {x = -1300, y = -80}, -- 1761
		dialog = {start = { -- 1762
			{speaker = "npc", name = "ta", text = "我的身体...好像越来越轻..."}, -- 1764
			{speaker = "npc", name = "ta", text = "像是要飘走了..."}, -- 1765
			{speaker = "player", name = "你", text = "我抓着你。不会让你飘走的。"}, -- 1766
			{speaker = "npc", name = "ta", text = "你一直在吗？"}, -- 1767
			{speaker = "player", name = "你", text = "每天都在。"}, -- 1768
			{speaker = "npc", name = "ta", text = "多久了？"}, -- 1770
			{speaker = "player", name = "你", text = "不重要。你在就好"}, -- 1771
			{speaker = "npc", name = "ta", text = "..."}, -- 1772
			{speaker = "npc", name = "ta", text = "..."} -- 1773
		}, ["end"] = {}}, -- 1773
		intro = {title = "第三章", subtitle = "高空跳跃"}, -- 1777
		background = { -- 1781
			file = "Image/role/BlueSky.png", -- 1782
			width = 2640, -- 1783
			height = 1490, -- 1784
			parallax = 0.3, -- 1785
			animated = true, -- 1786
			frameWidth = 792, -- 1787
			frameHeight = 447, -- 1788
			frames = 9, -- 1789
			duration = 1.8 -- 1790
		} -- 1790
	}, -- 1790
	{ -- 1794
		playerStart = {x = -800, y = -150}, -- 1795
		cameraLimitX = {min = -1000, max = 1000}, -- 1796
		platforms = { -- 1798
			{ -- 1800
				x = -1920, -- 1800
				y = -400, -- 1800
				w = 1920, -- 1800
				h = 490, -- 1800
				file = "Image/ground.png" -- 1800
			}, -- 1800
			{ -- 1801
				x = 0, -- 1801
				y = -400, -- 1801
				w = 1920, -- 1801
				h = 490, -- 1801
				file = "Image/ground.png" -- 1801
			}, -- 1801
			{ -- 1803
				x = 1920, -- 1803
				y = -400, -- 1803
				w = 1920, -- 1803
				h = 490, -- 1803
				file = "Image/ground.png" -- 1803
			}, -- 1803
			{ -- 1809
				x = -800, -- 1809
				y = 200, -- 1809
				w = 200, -- 1809
				h = 500, -- 1809
				file = "Image/platform2.png" -- 1809
			}, -- 1809
			{ -- 1810
				x = -450, -- 1810
				y = 300, -- 1810
				w = 200, -- 1810
				h = 600, -- 1810
				file = "Image/platform2.png" -- 1810
			}, -- 1810
			{ -- 1812
				x = -100, -- 1812
				y = 100, -- 1812
				w = 100, -- 1812
				h = 20, -- 1812
				file = "Image/platform.png" -- 1812
			}, -- 1812
			{ -- 1813
				x = 100, -- 1813
				y = 100, -- 1813
				w = 100, -- 1813
				h = 20, -- 1813
				file = "Image/platform.png" -- 1813
			}, -- 1813
			{ -- 1814
				x = 300, -- 1814
				y = 100, -- 1814
				w = 100, -- 1814
				h = 20, -- 1814
				file = "Image/platform.png" -- 1814
			}, -- 1814
			{ -- 1815
				x = 500, -- 1815
				y = 100, -- 1815
				w = 100, -- 1815
				h = 20, -- 1815
				file = "Image/platform.png" -- 1815
			}, -- 1815
			{ -- 1816
				x = 700, -- 1816
				y = 100, -- 1816
				w = 100, -- 1816
				h = 20, -- 1816
				file = "Image/platform.png" -- 1816
			}, -- 1816
			{ -- 1817
				x = 800, -- 1817
				y = -40, -- 1817
				w = 100, -- 1817
				h = 300, -- 1817
				file = "Image/platform2.png" -- 1817
			}, -- 1817
			{ -- 1818
				x = 1500, -- 1818
				y = 360, -- 1818
				w = 200, -- 1818
				h = 50, -- 1818
				file = "Image/platform.png" -- 1818
			}, -- 1818
			{ -- 1820
				x = 630, -- 1820
				y = 260, -- 1820
				w = 70, -- 1820
				h = 20, -- 1820
				file = "Image/platform.png" -- 1820
			}, -- 1820
			{ -- 1821
				x = 430, -- 1821
				y = 260, -- 1821
				w = 70, -- 1821
				h = 20, -- 1821
				file = "Image/platform.png" -- 1821
			}, -- 1821
			{ -- 1822
				x = 230, -- 1822
				y = 260, -- 1822
				w = 70, -- 1822
				h = 20, -- 1822
				file = "Image/platform.png" -- 1822
			}, -- 1822
			{ -- 1823
				x = 30, -- 1823
				y = 260, -- 1823
				w = 70, -- 1823
				h = 20, -- 1823
				file = "Image/platform.png" -- 1823
			}, -- 1823
			{ -- 1824
				x = -170, -- 1824
				y = 260, -- 1824
				w = 70, -- 1824
				h = 20, -- 1824
				file = "Image/platform.png" -- 1824
			}, -- 1824
			{ -- 1831
				x = -1900, -- 1831
				y = 225, -- 1831
				w = 220, -- 1831
				h = 1200, -- 1831
				file = "Image/Leftwall.png" -- 1831
			}, -- 1831
			{ -- 1832
				x = 1900, -- 1832
				y = 225, -- 1832
				w = 220, -- 1832
				h = 1200, -- 1832
				file = "Image/Rightwall.png" -- 1832
			} -- 1832
		}, -- 1832
		hazards = { -- 1835
			{ -- 1837
				x = 630, -- 1837
				y = 250, -- 1837
				w = 70, -- 1837
				h = 20, -- 1837
				file = "Image/trapdown.png" -- 1837
			}, -- 1837
			{ -- 1838
				x = 430, -- 1838
				y = 250, -- 1838
				w = 70, -- 1838
				h = 20, -- 1838
				file = "Image/trapdown.png" -- 1838
			}, -- 1838
			{ -- 1839
				x = 230, -- 1839
				y = 250, -- 1839
				w = 70, -- 1839
				h = 20, -- 1839
				file = "Image/trapdown.png" -- 1839
			}, -- 1839
			{ -- 1840
				x = 30, -- 1840
				y = 250, -- 1840
				w = 70, -- 1840
				h = 20, -- 1840
				file = "Image/trapdown.png" -- 1840
			}, -- 1840
			{ -- 1841
				x = -170, -- 1841
				y = 250, -- 1841
				w = 70, -- 1841
				h = 20, -- 1841
				file = "Image/trapdown.png" -- 1841
			}, -- 1841
			{ -- 1843
				x = 630, -- 1843
				y = -150, -- 1843
				w = 100, -- 1843
				h = 20, -- 1843
				file = "Image/trapup.png" -- 1843
			}, -- 1843
			{ -- 1844
				x = 530, -- 1844
				y = -150, -- 1844
				w = 100, -- 1844
				h = 20, -- 1844
				file = "Image/trapup.png" -- 1844
			}, -- 1844
			{ -- 1845
				x = 430, -- 1845
				y = -150, -- 1845
				w = 100, -- 1845
				h = 20, -- 1845
				file = "Image/trapup.png" -- 1845
			}, -- 1845
			{ -- 1846
				x = 330, -- 1846
				y = -150, -- 1846
				w = 100, -- 1846
				h = 20, -- 1846
				file = "Image/trapup.png" -- 1846
			}, -- 1846
			{ -- 1847
				x = 230, -- 1847
				y = -150, -- 1847
				w = 100, -- 1847
				h = 20, -- 1847
				file = "Image/trapup.png" -- 1847
			}, -- 1847
			{ -- 1848
				x = 130, -- 1848
				y = -150, -- 1848
				w = 100, -- 1848
				h = 20, -- 1848
				file = "Image/trapup.png" -- 1848
			}, -- 1848
			{ -- 1849
				x = 30, -- 1849
				y = -150, -- 1849
				w = 100, -- 1849
				h = 20, -- 1849
				file = "Image/trapup.png" -- 1849
			} -- 1849
		}, -- 1849
		goal = {x = 1500, y = 460, size = 40}, -- 1852
		collectible = {x = -800, y = 500, file = "Image/pink1.png"}, -- 1853
		npc = {x = -1000, y = -80}, -- 1854
		dialog = {start = { -- 1855
			{speaker = "npc", name = "ta", text = "我想起来了...我推开过你..."}, -- 1857
			{speaker = "npc", name = "ta", text = "我不想让你看见我...那个样子..."}, -- 1858
			{speaker = "player", name = "你", text = "什么样子都是你。"}, -- 1859
			{speaker = "npc", name = "ta", text = "我以为离开你...你会轻松一些..."}, -- 1860
			{speaker = "npc", name = "ta", text = "对不起..."}, -- 1861
			{speaker = "player", name = "你", text = "别说了，走吧。"}, -- 1862
			{speaker = "npc", name = "ta", text = "..."}, -- 1863
			{speaker = "npc", name = "ta", text = "..."} -- 1864
		}, ["end"] = {}}, -- 1864
		intro = {title = "第四章", subtitle = "曲折迷宫"}, -- 1868
		background = {file = "Image/bg2.png", width = 2880, height = 1800, parallax = 0.38} -- 1872
	}, -- 1872
	{ -- 1880
		playerStart = {x = -800, y = 50}, -- 1881
		cameraLimitX = {min = -1000, max = 1000}, -- 1882
		texts = {{ -- 1883
			x = -800, -- 1884
			y = 100, -- 1884
			text = "别被后面的墙追上！", -- 1884
			fontSize = 20, -- 1884
			showDistance = 200 -- 1884
		}}, -- 1884
		platforms = { -- 1887
			{ -- 1889
				x = -1920, -- 1889
				y = -390, -- 1889
				w = 1920, -- 1889
				h = 490, -- 1889
				file = "Image/ground.png" -- 1889
			}, -- 1889
			{ -- 1890
				x = 0, -- 1890
				y = -390, -- 1890
				w = 1920, -- 1890
				h = 490, -- 1890
				file = "Image/ground.png" -- 1890
			}, -- 1890
			{ -- 1892
				x = 1920, -- 1892
				y = -390, -- 1892
				w = 1920, -- 1892
				h = 490, -- 1892
				file = "Image/ground.png" -- 1892
			}, -- 1892
			{ -- 1898
				x = -800, -- 1898
				y = -100, -- 1898
				w = 150, -- 1898
				h = 225, -- 1898
				file = "Image/platform2.png" -- 1898
			}, -- 1898
			{ -- 1899
				x = -300, -- 1899
				y = -50, -- 1899
				w = 100, -- 1899
				h = 20, -- 1899
				file = "Image/platform.png" -- 1899
			}, -- 1899
			{ -- 1901
				x = 300, -- 1901
				y = 400, -- 1901
				w = 200, -- 1901
				h = 20, -- 1901
				file = "Image/platform.png" -- 1901
			}, -- 1901
			{ -- 1902
				x = 600, -- 1902
				y = 0, -- 1902
				w = 200, -- 1902
				h = 20, -- 1902
				file = "Image/platform.png" -- 1902
			}, -- 1902
			{ -- 1903
				x = 1000, -- 1903
				y = -50, -- 1903
				w = 200, -- 1903
				h = 500, -- 1903
				file = "Image/platform2.png" -- 1903
			}, -- 1903
			{ -- 1910
				x = -1920, -- 1910
				y = 1420, -- 1910
				w = 1920, -- 1910
				h = 480, -- 1910
				file = "Image/TopWall.png" -- 1910
			}, -- 1910
			{ -- 1911
				x = 0, -- 1911
				y = 1420, -- 1911
				w = 1920, -- 1911
				h = 480, -- 1911
				file = "Image/TopWall.png" -- 1911
			}, -- 1911
			{ -- 1913
				x = 1920, -- 1913
				y = 1420, -- 1913
				w = 1920, -- 1913
				h = 480, -- 1913
				file = "Image/TopWall.png" -- 1913
			}, -- 1913
			{ -- 1915
				x = -1900, -- 1915
				y = 225, -- 1915
				w = 220, -- 1915
				h = 1200, -- 1915
				file = "Image/LeftWall.png" -- 1915
			}, -- 1915
			{ -- 1916
				x = 1900, -- 1916
				y = 225, -- 1916
				w = 220, -- 1916
				h = 1200, -- 1916
				file = "Image/RightWall.png" -- 1916
			} -- 1916
		}, -- 1916
		movingSpikes = {{ -- 1918
			startX = -1800, -- 1920
			endX = 1000, -- 1921
			y = 300, -- 1922
			width = 800, -- 1923
			height = 1000, -- 1924
			speed = 50, -- 1925
			delay = 7 -- 1926
		}}, -- 1926
		hazards = { -- 1929
			{ -- 1930
				x = -630, -- 1930
				y = -140, -- 1930
				w = 100, -- 1930
				h = 20, -- 1930
				file = "Image/trapup.png" -- 1930
			}, -- 1930
			{ -- 1931
				x = -530, -- 1931
				y = -140, -- 1931
				w = 100, -- 1931
				h = 20, -- 1931
				file = "Image/trapup.png" -- 1931
			}, -- 1931
			{ -- 1932
				x = -430, -- 1932
				y = -140, -- 1932
				w = 100, -- 1932
				h = 20, -- 1932
				file = "Image/trapup.png" -- 1932
			}, -- 1932
			{ -- 1933
				x = -330, -- 1933
				y = -140, -- 1933
				w = 100, -- 1933
				h = 20, -- 1933
				file = "Image/trapup.png" -- 1933
			}, -- 1933
			{ -- 1934
				x = -230, -- 1934
				y = -140, -- 1934
				w = 100, -- 1934
				h = 20, -- 1934
				file = "Image/trapup.png" -- 1934
			}, -- 1934
			{ -- 1935
				x = -130, -- 1935
				y = -140, -- 1935
				w = 100, -- 1935
				h = 20, -- 1935
				file = "Image/trapup.png" -- 1935
			}, -- 1935
			{ -- 1936
				x = -30, -- 1936
				y = -140, -- 1936
				w = 100, -- 1936
				h = 20, -- 1936
				file = "Image/trapup.png" -- 1936
			}, -- 1936
			{ -- 1937
				x = 70, -- 1937
				y = -140, -- 1937
				w = 100, -- 1937
				h = 20, -- 1937
				file = "Image/trapup.png" -- 1937
			}, -- 1937
			{ -- 1938
				x = 670, -- 1938
				y = -140, -- 1938
				w = 100, -- 1938
				h = 20, -- 1938
				file = "Image/trapup.png" -- 1938
			}, -- 1938
			{ -- 1939
				x = 570, -- 1939
				y = -140, -- 1939
				w = 100, -- 1939
				h = 20, -- 1939
				file = "Image/trapup.png" -- 1939
			}, -- 1939
			{ -- 1940
				x = 470, -- 1940
				y = -140, -- 1940
				w = 100, -- 1940
				h = 20, -- 1940
				file = "Image/trapup.png" -- 1940
			}, -- 1940
			{ -- 1941
				x = 370, -- 1941
				y = -140, -- 1941
				w = 100, -- 1941
				h = 20, -- 1941
				file = "Image/trapup.png" -- 1941
			}, -- 1941
			{ -- 1942
				x = 270, -- 1942
				y = -140, -- 1942
				w = 100, -- 1942
				h = 20, -- 1942
				file = "Image/trapup.png" -- 1942
			}, -- 1942
			{ -- 1943
				x = 170, -- 1943
				y = -140, -- 1943
				w = 100, -- 1943
				h = 20, -- 1943
				file = "Image/trapup.png" -- 1943
			}, -- 1943
			{ -- 1944
				x = 770, -- 1944
				y = -140, -- 1944
				w = 100, -- 1944
				h = 20, -- 1944
				file = "Image/trapup.png" -- 1944
			} -- 1944
		}, -- 1944
		goal = {x = 1700, y = 0, size = 40}, -- 1950
		collectible = {x = 300, y = 500, file = "Image/green1.png"}, -- 1951
		npc = {x = 1600, y = -80}, -- 1952
		dialog = {start = { -- 1953
			{speaker = "npc", name = "ta", text = "有人在读书...我听见过..."}, -- 1955
			{speaker = "player", name = "你", text = "你最喜欢的那本。我读了很多遍。"}, -- 1956
			{speaker = "npc", name = "ta", text = "我听见了...但说不了话..."}, -- 1957
			{speaker = "player", name = "你", text = "我知道。你的手动了一下。"}, -- 1958
			{speaker = "player", name = "你", text = "那天我高兴了很久。"}, -- 1959
			{speaker = "npc", name = "ta", text = "..."}, -- 1960
			{speaker = "npc", name = "ta", text = "..."} -- 1961
		}, ["end"] = {}}, -- 1961
		intro = {title = "第五章", subtitle = "危险地带"}, -- 1965
		background = {file = "Image/bg2.png", width = 3000, height = 1800, parallax = 0.38} -- 1969
	}, -- 1969
	{ -- 1977
		playerStart = {x = -800, y = 200}, -- 1978
		cameraLimitX = {min = -1000, max = 1000}, -- 1979
		platforms = { -- 1980
			{ -- 1983
				x = -1920, -- 1983
				y = -440, -- 1983
				w = 1920, -- 1983
				h = 490, -- 1983
				file = "Image/ground.png" -- 1983
			}, -- 1983
			{ -- 1984
				x = 0, -- 1984
				y = -440, -- 1984
				w = 1920, -- 1984
				h = 490, -- 1984
				file = "Image/ground.png" -- 1984
			}, -- 1984
			{ -- 1986
				x = 1920, -- 1986
				y = -440, -- 1986
				w = 1920, -- 1986
				h = 490, -- 1986
				file = "Image/ground.png" -- 1986
			}, -- 1986
			{ -- 1992
				x = -800, -- 1992
				y = -130, -- 1992
				w = 200, -- 1992
				h = 150, -- 1992
				file = "Image/platform2.png" -- 1992
			}, -- 1992
			{ -- 1993
				x = -550, -- 1993
				y = 300, -- 1993
				w = 200, -- 1993
				h = 450, -- 1993
				file = "Image/platform2.png" -- 1993
			}, -- 1993
			{ -- 1994
				x = -200, -- 1994
				y = 300, -- 1994
				w = 200, -- 1994
				h = 400, -- 1994
				file = "Image/platform2.png" -- 1994
			}, -- 1994
			{ -- 1996
				x = -300, -- 1996
				y = -50, -- 1996
				w = 150, -- 1996
				h = 20, -- 1996
				file = "Image/platform.png" -- 1996
			}, -- 1996
			{ -- 1997
				x = 0, -- 1997
				y = 0, -- 1997
				w = 200, -- 1997
				h = 20, -- 1997
				file = "Image/platform.png" -- 1997
			}, -- 1997
			{ -- 1998
				x = 200, -- 1998
				y = 0, -- 1998
				w = 200, -- 1998
				h = 20, -- 1998
				file = "Image/platform.png" -- 1998
			}, -- 1998
			{ -- 2000
				x = 300, -- 2000
				y = 400, -- 2000
				w = 200, -- 2000
				h = 50, -- 2000
				file = "Image/platform.png" -- 2000
			}, -- 2000
			{ -- 2001
				x = 600, -- 2001
				y = -100, -- 2001
				w = 200, -- 2001
				h = 200, -- 2001
				file = "Image/platform2.png" -- 2001
			}, -- 2001
			{ -- 2002
				x = 600, -- 2002
				y = 300, -- 2002
				w = 200, -- 2002
				h = 200, -- 2002
				file = "Image/platform1.png" -- 2002
			}, -- 2002
			{ -- 2003
				x = 1000, -- 2003
				y = 50, -- 2003
				w = 200, -- 2003
				h = 500, -- 2003
				file = "Image/platform2.png" -- 2003
			}, -- 2003
			{ -- 2011
				x = -1920, -- 2011
				y = 1420, -- 2011
				w = 1920, -- 2011
				h = 480, -- 2011
				file = "Image/TopWall.png" -- 2011
			}, -- 2011
			{ -- 2012
				x = 0, -- 2012
				y = 1420, -- 2012
				w = 1920, -- 2012
				h = 480, -- 2012
				file = "Image/TopWall.png" -- 2012
			}, -- 2012
			{ -- 2014
				x = 1920, -- 2014
				y = 1420, -- 2014
				w = 1920, -- 2014
				h = 480, -- 2014
				file = "Image/TopWall.png" -- 2014
			}, -- 2014
			{ -- 2016
				x = -1900, -- 2016
				y = 225, -- 2016
				w = 220, -- 2016
				h = 1200, -- 2016
				file = "Image/LeftWall.png" -- 2016
			}, -- 2016
			{ -- 2017
				x = 1900, -- 2017
				y = 225, -- 2017
				w = 220, -- 2017
				h = 1200, -- 2017
				file = "Image/RightWall.png" -- 2017
			} -- 2017
		}, -- 2017
		movingSpikes = {{ -- 2019
			startX = -1800, -- 2021
			endX = 1000, -- 2022
			y = 300, -- 2023
			width = 800, -- 2024
			height = 1000, -- 2025
			speed = 50, -- 2026
			delay = 7 -- 2027
		}}, -- 2027
		hazards = { -- 2030
			{ -- 2031
				x = 600, -- 2031
				y = 10, -- 2031
				w = 200, -- 2031
				h = 20, -- 2031
				file = "Image/trapup.png" -- 2031
			}, -- 2031
			{ -- 2032
				x = 600, -- 2032
				y = 400, -- 2032
				w = 200, -- 2032
				h = 20, -- 2032
				file = "Image/trapup.png" -- 2032
			}, -- 2032
			{ -- 2033
				x = 600, -- 2033
				y = 190, -- 2033
				w = 200, -- 2033
				h = 20, -- 2033
				file = "Image/trapdown.png" -- 2033
			}, -- 2033
			{ -- 2034
				x = -630, -- 2034
				y = -190, -- 2034
				w = 100, -- 2034
				h = 20, -- 2034
				file = "Image/trapup.png" -- 2034
			}, -- 2034
			{ -- 2035
				x = -530, -- 2035
				y = -190, -- 2035
				w = 100, -- 2035
				h = 20, -- 2035
				file = "Image/trapup.png" -- 2035
			}, -- 2035
			{ -- 2036
				x = -430, -- 2036
				y = -190, -- 2036
				w = 100, -- 2036
				h = 20, -- 2036
				file = "Image/trapup.png" -- 2036
			}, -- 2036
			{ -- 2037
				x = -330, -- 2037
				y = -190, -- 2037
				w = 100, -- 2037
				h = 20, -- 2037
				file = "Image/trapup.png" -- 2037
			}, -- 2037
			{ -- 2038
				x = -230, -- 2038
				y = -190, -- 2038
				w = 100, -- 2038
				h = 20, -- 2038
				file = "Image/trapup.png" -- 2038
			}, -- 2038
			{ -- 2039
				x = -130, -- 2039
				y = -190, -- 2039
				w = 100, -- 2039
				h = 20, -- 2039
				file = "Image/trapup.png" -- 2039
			} -- 2039
		}, -- 2039
		goal = {x = 1700, y = 0, size = 40}, -- 2043
		collectible = {x = -350, y = 500, file = "Image/yellow1.png"}, -- 2044
		npc = {x = 1500, y = -110}, -- 2045
		dialog = {start = { -- 2046
			{speaker = "npc", name = "ta", text = "我想起来了...你在哭..."}, -- 2048
			{speaker = "npc", name = "ta", text = "你抓着我的手...说不许走..."}, -- 2049
			{speaker = "player", name = "你", text = "你听到了？"}, -- 2050
			{speaker = "npc", name = "ta", text = "我想回应你...但睁不开眼睛..."}, -- 2051
			{speaker = "npc", name = "ta", text = "我在这里等了很久...等你来找我..."}, -- 2052
			{speaker = "player", name = "你", text = "我来了。"}, -- 2053
			{speaker = "npc", name = "ta", text = "嗯...这次我不会松手了。"}, -- 2054
			{speaker = "npc", name = "ta", text = "..."}, -- 2055
			{speaker = "npc", name = "ta", text = "..."} -- 2056
		}, ["end"] = {}}, -- 2056
		intro = {title = "第六章", subtitle = "极限跳跃"}, -- 2060
		background = {file = "Image/bg2.png", width = 2880, height = 1800, parallax = 0.38} -- 2064
	}, -- 2064
	{ -- 2072
		playerStart = {x = -800, y = 250}, -- 2073
		cameraLimitX = {min = -1000, max = 1000}, -- 2074
		texts = { -- 2075
			{ -- 2076
				x = -800, -- 2076
				y = 100, -- 2076
				text = "<--  ?",
				fontSize = 20, -- 2076
				showDistance = 200 -- 2076
			}, -- 2076
			{ -- 2077
				x = -1000, -- 2077
				y = 0, -- 2077
				text = "<--  ?",
				fontSize = 20, -- 2077
				showDistance = 200 -- 2077
			}, -- 2077
			{ -- 2078
				x = -1200, -- 2078
				y = 0, -- 2078
				text = "<--  ?",
				fontSize = 20, -- 2078
				showDistance = 200 -- 2078
			}, -- 2078
			{ -- 2079
				x = -1200, -- 2079
				y = -50, -- 2079
				text = "这是一条不归路...除非...?", -- 2079
				fontSize = 20, -- 2079
				showDistance = 200 -- 2079
			}, -- 2079
			{ -- 2080
				x = 1600, -- 2080
				y = 400, -- 2080
				text = "这里...是终点...吗？", -- 2080
				fontSize = 20, -- 2080
				showDistance = 200 -- 2080
			} -- 2080
		}, -- 2080
		platforms = { -- 2082
			{ -- 2084
				x = -1920, -- 2084
				y = -400, -- 2084
				w = 1920, -- 2084
				h = 490, -- 2084
				file = "Image/ground.png" -- 2084
			}, -- 2084
			{ -- 2085
				x = 0, -- 2085
				y = -400, -- 2085
				w = 1920, -- 2085
				h = 490, -- 2085
				file = "Image/ground.png" -- 2085
			}, -- 2085
			{ -- 2087
				x = 1920, -- 2087
				y = -400, -- 2087
				w = 1920, -- 2087
				h = 490, -- 2087
				file = "Image/ground.png" -- 2087
			}, -- 2087
			{ -- 2092
				x = -800, -- 2092
				y = -100, -- 2092
				w = 200, -- 2092
				h = 150, -- 2092
				file = "Image/platform2.png" -- 2092
			}, -- 2092
			{ -- 2093
				x = -300, -- 2093
				y = 300, -- 2093
				w = 200, -- 2093
				h = 400, -- 2093
				file = "Image/platform2.png" -- 2093
			}, -- 2093
			{ -- 2094
				x = 100, -- 2094
				y = 300, -- 2094
				w = 200, -- 2094
				h = 400, -- 2094
				file = "Image/platform2.png" -- 2094
			}, -- 2094
			{ -- 2097
				x = 0, -- 2097
				y = -50, -- 2097
				w = 150, -- 2097
				h = 20, -- 2097
				file = "Image/platform.png" -- 2097
			}, -- 2097
			{ -- 2098
				x = 600, -- 2098
				y = -20, -- 2098
				w = 150, -- 2098
				h = 350, -- 2098
				file = "Image/platform2.png" -- 2098
			}, -- 2098
			{ -- 2099
				x = 600, -- 2099
				y = 500, -- 2099
				w = 150, -- 2099
				h = 300, -- 2099
				file = "Image/platform1.png" -- 2099
			}, -- 2099
			{ -- 2105
				x = 200, -- 2105
				y = -50, -- 2105
				w = 20, -- 2105
				h = 300, -- 2105
				file = "Image/platform2.png" -- 2105
			}, -- 2105
			{ -- 2107
				x = 1600, -- 2107
				y = 50, -- 2107
				w = 200, -- 2107
				h = 500, -- 2107
				file = "Image/platform2.png" -- 2107
			}, -- 2107
			{ -- 2114
				x = -1920, -- 2114
				y = 1420, -- 2114
				w = 1920, -- 2114
				h = 480, -- 2114
				file = "Image/TopWall.png" -- 2114
			}, -- 2114
			{ -- 2115
				x = 0, -- 2115
				y = 1420, -- 2115
				w = 1920, -- 2115
				h = 480, -- 2115
				file = "Image/TopWall.png" -- 2115
			}, -- 2115
			{ -- 2117
				x = 1920, -- 2117
				y = 1420, -- 2117
				w = 1920, -- 2117
				h = 480, -- 2117
				file = "Image/TopWall.png" -- 2117
			}, -- 2117
			{ -- 2119
				x = -1900, -- 2119
				y = 225, -- 2119
				w = 220, -- 2119
				h = 1200, -- 2119
				file = "Image/LeftWall.png" -- 2119
			}, -- 2119
			{ -- 2120
				x = 1900, -- 2120
				y = 225, -- 2120
				w = 220, -- 2120
				h = 1200, -- 2120
				file = "Image/RightWall.png" -- 2120
			} -- 2120
		}, -- 2120
		movingSpikes = {{ -- 2122
			startX = -1800, -- 2124
			endX = 1000, -- 2125
			y = 300, -- 2126
			width = 800, -- 2127
			height = 1000, -- 2128
			speed = 50, -- 2129
			delay = 12 -- 2130
		}}, -- 2130
		hazards = { -- 2133
			{ -- 2136
				x = -630, -- 2136
				y = -150, -- 2136
				w = 100, -- 2136
				h = 20, -- 2136
				file = "Image/trapup.png" -- 2136
			}, -- 2136
			{ -- 2137
				x = -530, -- 2137
				y = -150, -- 2137
				w = 100, -- 2137
				h = 20, -- 2137
				file = "Image/trapup.png" -- 2137
			}, -- 2137
			{ -- 2138
				x = -430, -- 2138
				y = -150, -- 2138
				w = 100, -- 2138
				h = 20, -- 2138
				file = "Image/trapup.png" -- 2138
			}, -- 2138
			{ -- 2139
				x = -330, -- 2139
				y = -150, -- 2139
				w = 100, -- 2139
				h = 20, -- 2139
				file = "Image/trapup.png" -- 2139
			}, -- 2139
			{ -- 2140
				x = -230, -- 2140
				y = -150, -- 2140
				w = 100, -- 2140
				h = 20, -- 2140
				file = "Image/trapup.png" -- 2140
			}, -- 2140
			{ -- 2141
				x = -130, -- 2141
				y = -150, -- 2141
				w = 100, -- 2141
				h = 20, -- 2141
				file = "Image/trapup.png" -- 2141
			}, -- 2141
			{ -- 2142
				x = 600, -- 2142
				y = 160, -- 2142
				w = 150, -- 2142
				h = 20, -- 2142
				file = "Image/trapup.png" -- 2142
			}, -- 2142
			{ -- 2143
				x = 600, -- 2143
				y = 650, -- 2143
				w = 150, -- 2143
				h = 20, -- 2143
				file = "Image/trapup.png" -- 2143
			}, -- 2143
			{ -- 2144
				x = 600, -- 2144
				y = 340, -- 2144
				w = 150, -- 2144
				h = 20, -- 2144
				file = "Image/trapdown.png" -- 2144
			} -- 2144
		}, -- 2144
		goal = {x = 1600, y = 550, size = 40}, -- 2146
		secretGoal = {x = -1400, y = 0, size = 30, targetLevel = 7}, -- 2147
		collectible = {x = -300, y = 550, file = "Image/red1.png"}, -- 2148
		npc = {x = 100, y = 550}, -- 2149
		dialog = {start = { -- 2150
			{speaker = "npc", name = "ta", text = "走吧，一起回家。"}, -- 2152
			{speaker = "player", name = "你", text = "嗯。"}, -- 2153
			{speaker = "npc", name = "ta", text = "你先走，我跟着你。"}, -- 2154
			{speaker = "player", name = "你", text = "一起。"}, -- 2155
			{speaker = "npc", name = "ta", text = "好...一起..."}, -- 2156
			{speaker = "npc", name = "ta", text = "..."}, -- 2157
			{speaker = "npc", name = "ta", text = "..."} -- 2158
		}, ["end"] = {}}, -- 2158
		intro = {title = "第七章", subtitle = "终极试炼"}, -- 2164
		background = { -- 2168
			file = "Image/role/BlueSky.png", -- 2169
			width = 2640, -- 2170
			height = 1490, -- 2171
			parallax = 0.3, -- 2172
			animated = true, -- 2173
			frameWidth = 792, -- 2174
			frameHeight = 447, -- 2175
			frames = 9, -- 2176
			duration = 1.8 -- 2177
		} -- 2177
	}, -- 2177
	{ -- 2182
		playerStart = {x = -900, y = 100}, -- 2183
		cameraLimitX = {min = -500, max = 1000}, -- 2184
		texts = {{ -- 2185
			x = -900, -- 2186
			y = 0, -- 2186
			text = "你失去了一切...除了...桥", -- 2186
			fontSize = 20, -- 2186
			showDistance = 200 -- 2186
		}}, -- 2186
		platforms = { -- 2189
			{ -- 2192
				x = -1920, -- 2192
				y = -400, -- 2192
				w = 1920, -- 2192
				h = 490, -- 2192
				file = "Image/ground.png" -- 2192
			}, -- 2192
			{ -- 2193
				x = 0, -- 2193
				y = -400, -- 2193
				w = 1920, -- 2193
				h = 490, -- 2193
				file = "Image/ground.png" -- 2193
			}, -- 2193
			{ -- 2195
				x = 1920, -- 2195
				y = -400, -- 2195
				w = 1920, -- 2195
				h = 490, -- 2195
				file = "Image/ground.png" -- 2195
			}, -- 2195
			{ -- 2199
				x = 400, -- 2199
				y = 150, -- 2199
				w = 250, -- 2199
				h = 20, -- 2199
				file = "Image/platform.png" -- 2199
			}, -- 2199
			{ -- 2200
				x = -100, -- 2200
				y = 50, -- 2200
				w = 200, -- 2200
				h = 20, -- 2200
				file = "Image/platform.png" -- 2200
			}, -- 2200
			{ -- 2201
				x = -500, -- 2201
				y = -50, -- 2201
				w = 200, -- 2201
				h = 20, -- 2201
				file = "Image/platform.png" -- 2201
			}, -- 2201
			{ -- 2202
				x = -900, -- 2202
				y = -150, -- 2202
				w = 200, -- 2202
				h = 20, -- 2202
				file = "Image/platform.png" -- 2202
			}, -- 2202
			{ -- 2215
				x = -1100, -- 2215
				y = 225, -- 2215
				w = 200, -- 2215
				h = 1200, -- 2215
				file = "Image/LeftWall.png" -- 2215
			}, -- 2215
			{ -- 2216
				x = 600, -- 2216
				y = 225, -- 2216
				w = 200, -- 2216
				h = 1200, -- 2216
				file = "Image/RightWall.png" -- 2216
			} -- 2216
		}, -- 2216
		hazards = {}, -- 2218
		goal = {x = 420, y = 190, size = 40}, -- 2221
		npc = {x = 320, y = 210}, -- 2222
		dialog = {start = { -- 2223
			{speaker = "npc", name = "ta", text = "这里是...？"}, -- 2225
			{speaker = "player", name = "你", text = "找到所有记忆碎片...就能一起回去。"}, -- 2226
			{speaker = "npc", name = "ta", text = "......好。"}, -- 2227
			{speaker = "npc", name = "ta", text = "......"}, -- 2228
			{speaker = "npc", name = "ta", text = "......"} -- 2229
		}, ["end"] = {}}, -- 2229
		intro = {title = "???", subtitle = "隐藏试炼"}, -- 2233
		background = { -- 2237
			file = "Image/role/BlueSky.png", -- 2238
			width = 2640, -- 2239
			height = 1490, -- 2240
			parallax = 0.3, -- 2241
			animated = true, -- 2242
			frameWidth = 792, -- 2243
			frameHeight = 447, -- 2244
			frames = 9, -- 2245
			duration = 1.8 -- 2246
		}, -- 2246
		hidden = true -- 2248
	} -- 2248
} -- 2248
local function getVisibleLevelCount() -- 2253
	return #__TS__ArrayFilter( -- 2254
		LEVELS, -- 2254
		function(____, level) return not level.hidden end -- 2254
	) -- 2254
end -- 2253
local ENDING_DIALOGS = {fakeEnding = { -- 2268
	{speaker = "npc", text = "你走慢点...我有点累..."}, -- 2272
	{speaker = "player", text = "你的手好凉。"}, -- 2273
	{speaker = "npc", text = "没事...快到了..."}, -- 2274
	{speaker = "player", text = "我抓不住你了。"}, -- 2275
	{speaker = "npc", text = "我在...你往前走..."}, -- 2276
	{speaker = "player", text = "你在骗我。"}, -- 2277
	{speaker = "npc", text = "没有...我就在后面...一直都在..."}, -- 2278
	{speaker = "npc", text = "好好活下去..."} -- 2279
}, sacrificeEnding = { -- 2279
	{speaker = "npc", text = "我们到了...一起走吧。"}, -- 2284
	{speaker = "player", text = "你先走。"}, -- 2285
	{speaker = "npc", text = "你怎么不动？"}, -- 2286
	{speaker = "player", text = "有人要留下。"}, -- 2287
	{speaker = "npc", text = "...你骗我。"}, -- 2288
	{speaker = "player", text = "我说带你回去。没骗你。"}, -- 2289
	{speaker = "npc", text = "我不走。"}, -- 2290
	{speaker = "player", text = "带着我的灵魂回去"}, -- 2291
	{speaker = "player", text = "替我去看日出。"}, -- 2292
	{speaker = "player", text = "走吧。别回头。"} -- 2293
}, perfectEnding = {{speaker = "npc", text = "我们到了...一起走吧。"}, {speaker = "player", text = "走吧。一起去看日出。"}, {speaker = "npc", text = "好，一起回家"}, {speaker = "player", text = "一起回家。"}}} -- 2293
local function EndingScene(props) -- 2312
	local advanceDialog, advanceImage -- 2312
	local dialogIndexRef = useRef(0) -- 2313
	local imageIndexRef = useRef(0) -- 2314
	local phaseRef = useRef("dialog") -- 2315
	local lastSpacePressedRef = useRef(false) -- 2316
	local textLabelRef = useRef(nil) -- 2317
	local nameLabelRef = useRef(nil) -- 2318
	local avatarPlayerRef = useRef(nil) -- 2319
	local avatarNpcRef = useRef(nil) -- 2320
	local nameNodeRef = useRef(nil) -- 2321
	local avatarNodeRef = useRef(nil) -- 2322
	local dialogNodeRef = useRef(nil) -- 2323
	local imageNodeRef = useRef(nil) -- 2324
	local image0Ref = useRef(nil) -- 2326
	local image1Ref = useRef(nil) -- 2327
	local image2Ref = useRef(nil) -- 2328
	local image3Ref = useRef(nil) -- 2329
	local image4Ref = useRef(nil) -- 2330
	local image5Ref = useRef(nil) -- 2331
	local image6Ref = useRef(nil) -- 2332
	local image7Ref = useRef(nil) -- 2333
	local messages = ENDING_DIALOGS[props.dialogType] -- 2335
	local images = props.endingImages -- 2336
	local function hideAllImages() -- 2338
		if image0Ref.current then -- 2338
			image0Ref.current.visible = false -- 2339
		end -- 2339
		if image1Ref.current then -- 2339
			image1Ref.current.visible = false -- 2340
		end -- 2340
		if image2Ref.current then -- 2340
			image2Ref.current.visible = false -- 2341
		end -- 2341
		if image3Ref.current then -- 2341
			image3Ref.current.visible = false -- 2342
		end -- 2342
		if image4Ref.current then -- 2342
			image4Ref.current.visible = false -- 2343
		end -- 2343
		if image5Ref.current then -- 2343
			image5Ref.current.visible = false -- 2344
		end -- 2344
		if image6Ref.current then -- 2344
			image6Ref.current.visible = false -- 2345
		end -- 2345
		if image7Ref.current then -- 2345
			image7Ref.current.visible = false -- 2346
		end -- 2346
	end -- 2338
	local function showCurrentImage() -- 2349
		hideAllImages() -- 2350
		local index = imageIndexRef.current -- 2351
		if index == 0 and image0Ref.current then -- 2351
			image0Ref.current.visible = true -- 2352
		elseif index == 1 and image1Ref.current then -- 2352
			image1Ref.current.visible = true -- 2353
		elseif index == 2 and image2Ref.current then -- 2353
			image2Ref.current.visible = true -- 2354
		elseif index == 3 and image3Ref.current then -- 2354
			image3Ref.current.visible = true -- 2355
		elseif index == 4 and image4Ref.current then -- 2355
			image4Ref.current.visible = true -- 2356
		elseif index == 5 and image5Ref.current then -- 2356
			image5Ref.current.visible = true -- 2357
		elseif index == 6 and image6Ref.current then -- 2357
			image6Ref.current.visible = true -- 2358
		elseif index == 7 and image7Ref.current then -- 2358
			image7Ref.current.visible = true -- 2359
		end -- 2359
	end -- 2349
	local function updateDisplay() -- 2362
		local msg = messages[dialogIndexRef.current] -- 2363
		if not msg then -- 2363
			return -- 2364
		end -- 2364
		local textLabel = textLabelRef.current -- 2366
		local nameLabel = nameLabelRef.current -- 2367
		local avatarPlayer = avatarPlayerRef.current -- 2368
		local avatarNpc = avatarNpcRef.current -- 2369
		local nameNode = nameNodeRef.current -- 2370
		local avatarNode = avatarNodeRef.current -- 2371
		if textLabel then -- 2371
			textLabel.text = msg.text -- 2373
		end -- 2373
		if nameLabel then -- 2373
			nameLabel.text = msg.speaker == "player" and "你" or "ta" -- 2374
		end -- 2374
		if avatarPlayer then -- 2374
			avatarPlayer.visible = msg.speaker == "player" -- 2376
		end -- 2376
		if avatarNpc then -- 2376
			avatarNpc.visible = msg.speaker ~= "player" -- 2377
		end -- 2377
		if nameNode then -- 2377
			nameNode.x = msg.speaker == "player" and -300 or 300 -- 2379
		end -- 2379
		if avatarNode then -- 2379
			avatarNode.x = msg.speaker == "player" and -340 or 340 -- 2382
		end -- 2382
	end -- 2362
	local function handleUpdate(deltaTime) -- 2386
		local spacePressed = Keyboard:isKeyPressed("Space") -- 2387
		local spaceDown = not lastSpacePressedRef.current and spacePressed -- 2388
		lastSpacePressedRef.current = spacePressed -- 2389
		if phaseRef.current == "dialog" then -- 2389
			if spaceDown then -- 2389
				advanceDialog() -- 2393
			end -- 2393
		elseif phaseRef.current == "image" then -- 2393
			if spaceDown then -- 2393
				advanceImage() -- 2397
			end -- 2397
		end -- 2397
		return false -- 2401
	end -- 2386
	advanceDialog = function() -- 2404
		dialogIndexRef.current = dialogIndexRef.current + 1 -- 2405
		if dialogIndexRef.current >= #messages then -- 2405
			phaseRef.current = "image" -- 2408
			imageIndexRef.current = 0 -- 2409
			local dialogNode = dialogNodeRef.current -- 2410
			local imageNode = imageNodeRef.current -- 2411
			if dialogNode then -- 2411
				dialogNode.visible = false -- 2412
			end -- 2412
			if imageNode then -- 2412
				imageNode.visible = true -- 2413
			end -- 2413
			showCurrentImage() -- 2414
		else -- 2414
			updateDisplay() -- 2416
		end -- 2416
	end -- 2404
	advanceImage = function() -- 2420
		imageIndexRef.current = imageIndexRef.current + 1 -- 2421
		if imageIndexRef.current >= #images then -- 2421
			props:onComplete() -- 2424
		else -- 2424
			showCurrentImage() -- 2427
		end -- 2427
	end -- 2420
	local function handleTap(touch) -- 2431
		if phaseRef.current == "dialog" then -- 2431
			advanceDialog() -- 2433
		elseif phaseRef.current == "image" then -- 2433
			advanceImage() -- 2435
		end -- 2435
		return true -- 2437
	end -- 2431
	local currentMsg = messages[dialogIndexRef.current] or messages[1] -- 2440
	local isPlayer = currentMsg.speaker == "player" -- 2441
	return React.createElement( -- 2443
		"node", -- 2443
		{onUpdate = handleUpdate, order = 3000, touchEnabled = true, onTapBegan = handleTap}, -- 2443
		React.createElement( -- 2443
			"draw-node", -- 2443
			nil, -- 2443
			React.createElement("rect-shape", {width = 3000, height = 3000, fillColor = 255}) -- 2443
		), -- 2443
		React.createElement( -- 2443
			"node", -- 2443
			{ref = dialogNodeRef, visible = true}, -- 2443
			React.createElement( -- 2443
				"node", -- 2443
				{y = -200}, -- 2443
				React.createElement("sprite", {width = 800, height = 200, opacity = 0.9}), -- 2443
				"  ", -- 2443
				React.createElement( -- 2443
					"node", -- 2443
					{ref = nameNodeRef, x = isPlayer and -350 or 300, y = 100}, -- 2443
					React.createElement("sprite", {width = 120, height = 36}), -- 2443
					"  ", -- 2443
					React.createElement("label", { -- 2443
						ref = nameLabelRef, -- 2443
						fontName = "sarasa-mono-sc-regular", -- 2443
						fontSize = 22, -- 2443
						text = isPlayer and "你" or "ta", -- 2443
						y = -5, -- 2443
						alignment = "Center" -- 2443
					}) -- 2443
				), -- 2443
				React.createElement( -- 2443
					"node", -- 2443
					{ref = avatarNodeRef, x = isPlayer and -340 or 340, y = 0}, -- 2443
					React.createElement("sprite", { -- 2443
						ref = avatarPlayerRef, -- 2443
						file = "Image/avatar_player.png", -- 2443
						width = 100, -- 2443
						height = 100, -- 2443
						filter = "Point", -- 2443
						visible = isPlayer -- 2443
					}), -- 2443
					React.createElement("sprite", { -- 2443
						ref = avatarNpcRef, -- 2443
						file = "Image/avatar_npc.png", -- 2443
						width = 100, -- 2443
						height = 100, -- 2443
						filter = "Point", -- 2443
						visible = not isPlayer -- 2443
					}) -- 2443
				), -- 2443
				React.createElement("label", { -- 2443
					ref = textLabelRef, -- 2443
					fontName = "sarasa-mono-sc-regular", -- 2443
					fontSize = 28, -- 2443
					text = currentMsg.text, -- 2443
					width = 500, -- 2443
					y = 0, -- 2443
					alignment = "Center" -- 2443
				}), -- 2443
				React.createElement( -- 2443
					"node", -- 2443
					{y = -80}, -- 2443
					React.createElement("label", { -- 2443
						fontName = "sarasa-mono-sc-regular", -- 2443
						fontSize = 18, -- 2443
						text = "按空格继续", -- 2443
						alignment = "Center", -- 2443
						opacity = 0.7 -- 2443
					}) -- 2443
				) -- 2443
			) -- 2443
		), -- 2443
		React.createElement( -- 2443
			"node", -- 2443
			{ref = imageNodeRef, visible = false}, -- 2443
			React.createElement( -- 2443
				"node", -- 2443
				{order = -10}, -- 2443
				React.createElement( -- 2443
					"draw-node", -- 2443
					nil, -- 2443
					React.createElement("rect-shape", { -- 2443
						x = -1500, -- 2443
						y = -1500, -- 2443
						width = 3000, -- 2443
						height = 3000, -- 2443
						fillColor = 4278190080 -- 2443
					}) -- 2443
				) -- 2443
			), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image0Ref, -- 2443
				file = images[1] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image1Ref, -- 2443
				file = images[2] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image2Ref, -- 2443
				file = images[3] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image3Ref, -- 2443
				file = images[4] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image4Ref, -- 2443
				file = images[5] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image5Ref, -- 2443
				file = images[6] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image6Ref, -- 2443
				file = images[7] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement("sprite", { -- 2443
				ref = image7Ref, -- 2443
				file = images[8] or "Image/cg/LostEnding-1.png", -- 2443
				width = 1000, -- 2443
				height = 1000, -- 2443
				filter = "Point", -- 2443
				visible = false -- 2443
			}), -- 2443
			React.createElement( -- 2443
				"node", -- 2443
				{y = -350}, -- 2443
				React.createElement("label", { -- 2443
					fontName = "sarasa-mono-sc-regular", -- 2443
					fontSize = 18, -- 2443
					text = "按空格继续", -- 2443
					alignment = "Center", -- 2443
					opacity = 0.7 -- 2443
				}) -- 2443
			) -- 2443
		) -- 2443
	) -- 2443
end -- 2312
local function TransitionAnim(props) -- 2552
	local timerRef = useRef(0) -- 2553
	local completedRef = useRef(false) -- 2554
	local spriteRef = useRef(nil) -- 2555
	local function handleUpdate(deltaTime) -- 2557
		if completedRef.current then -- 2557
			return false -- 2558
		end -- 2558
		timerRef.current = timerRef.current + deltaTime -- 2560
		if props.animFile and spriteRef.current and spriteRef.current.texture then -- 2560
			local sprite = spriteRef.current -- 2564
			local tex = sprite.texture -- 2565
			local texW = tex.width -- 2566
			local texH = tex.height -- 2567
			if texW > 0 and texH > 0 then -- 2567
				local fw = props.animFrameWidth or texW -- 2570
				local fh = props.animFrameHeight or texH -- 2571
				local frames = props.animFrames or 1 -- 2572
				local duration = props.animDuration or 3 -- 2573
				local cols = math.floor(texW / fw) -- 2574
				if cols > 0 then -- 2574
					local progress = timerRef.current / duration % 1 -- 2577
					local frameIndex = math.floor(progress * frames) -- 2578
					local col = frameIndex % cols -- 2579
					local row = math.floor(frameIndex / cols) -- 2580
					sprite.textureRect = Rect(col * fw, row * fh, fw, fh) -- 2582
				end -- 2582
			end -- 2582
		end -- 2582
		if timerRef.current >= 3 and not completedRef.current then -- 2582
			completedRef.current = true -- 2588
			props:onComplete() -- 2589
			return true -- 2590
		end -- 2590
		return false -- 2593
	end -- 2557
	local timer = timerRef.current -- 2596
	local fadeOpacity = 1 -- 2597
	if timer < 0.5 then -- 2597
		fadeOpacity = timer / 0.5 -- 2599
	elseif timer > 2.5 then -- 2599
		fadeOpacity = (3 - timer) / 0.5 -- 2601
	end -- 2601
	return React.createElement( -- 2604
		"node", -- 2604
		{onUpdate = handleUpdate, order = 3000}, -- 2604
		React.createElement( -- 2604
			"draw-node", -- 2604
			nil, -- 2604
			React.createElement("rect-shape", {width = 2000, height = 2000, fillColor = 238}) -- 2604
		), -- 2604
		props.animFile and React.createElement("sprite", {ref = spriteRef, file = props.animFile, filter = "Point", opacity = fadeOpacity}), -- 2611
		React.createElement( -- 2611
			"node", -- 2611
			{y = 50, opacity = fadeOpacity}, -- 2611
			React.createElement("label", { -- 2611
				fontName = "sarasa-mono-sc-regular", -- 2611
				fontSize = 48, -- 2611
				text = props.title, -- 2611
				y = -12, -- 2611
				alignment = "Center" -- 2611
			}) -- 2611
		), -- 2611
		React.createElement( -- 2611
			"node", -- 2611
			{y = -20, opacity = fadeOpacity}, -- 2611
			React.createElement("label", { -- 2611
				fontName = "sarasa-mono-sc-regular", -- 2611
				fontSize = 28, -- 2611
				text = props.subtitle, -- 2611
				y = -7, -- 2611
				alignment = "Center" -- 2611
			}) -- 2611
		) -- 2611
	) -- 2611
end -- 2552
local function SnowParticle(props) -- 2649
	local posRef = useRef({x = props.initialX, y = props.initialY}) -- 2650
	local nodeRef = useRef(nil) -- 2651
	local function handleUpdate(deltaTime) -- 2653
		local node = nodeRef.current -- 2654
		if not node then -- 2654
			return false -- 2655
		end -- 2655
		local ____posRef_current_1, ____y_2 = posRef.current, "y" -- 2655
		____posRef_current_1[____y_2] = ____posRef_current_1[____y_2] - props.speed * deltaTime -- 2657
		if posRef.current.y < -600 then -- 2657
			posRef.current.y = 600 -- 2660
			posRef.current.x = (math.random() - 0.5) * 1600 -- 2661
		end -- 2661
		node.x = posRef.current.x -- 2664
		node.y = posRef.current.y -- 2665
		return false -- 2667
	end -- 2653
	return React.createElement( -- 2670
		"node", -- 2670
		{ref = nodeRef, x = props.initialX, y = props.initialY, onUpdate = handleUpdate}, -- 2670
		React.createElement( -- 2670
			"draw-node", -- 2670
			nil, -- 2670
			React.createElement("dot-shape", {radius = props.size, color = 4294967295}) -- 2670
		) -- 2670
	) -- 2670
end -- 2649
local function LevelIntro(props) -- 2679
	local timerRef = useRef(0) -- 2680
	local completedRef = useRef(false) -- 2681
	local lastSpacePressedRef = useRef(false) -- 2682
	local snowParticlesRef = useRef({}) -- 2683
	if #snowParticlesRef.current == 0 then -- 2683
		do -- 2683
			local i = 0 -- 2686
			while i < 60 do -- 2686
				local ____snowParticlesRef_current_3 = snowParticlesRef.current -- 2686
				____snowParticlesRef_current_3[#____snowParticlesRef_current_3 + 1] = { -- 2687
					x = (math.random() - 0.5) * 1600, -- 2688
					y = (math.random() - 0.5) * 1000, -- 2689
					speed = math.random() * 100 + 60, -- 2690
					size = math.random() * 3 + 2 -- 2691
				} -- 2691
				i = i + 1 -- 2686
			end -- 2686
		end -- 2686
		____print("❄️ [LevelIntro] 开场动画开始") -- 2694
	end -- 2694
	local function handleUpdate(deltaTime) -- 2697
		if completedRef.current then -- 2697
			return false -- 2699
		end -- 2699
		timerRef.current = timerRef.current + deltaTime -- 2702
		local spacePressed = Keyboard:isKeyPressed("Space") -- 2704
		if not lastSpacePressedRef.current and spacePressed then -- 2704
			____print("⏭️ [LevelIntro] 跳过开场动画") -- 2706
			completedRef.current = true -- 2707
			props:onComplete() -- 2708
			return false -- 2709
		end -- 2709
		lastSpacePressedRef.current = spacePressed -- 2711
		if timerRef.current >= 3.5 then -- 2711
			____print("✅ [LevelIntro] 开场动画完成") -- 2714
			completedRef.current = true -- 2715
			props:onComplete() -- 2716
			return false -- 2717
		end -- 2717
		return false -- 2720
	end -- 2697
	local function handleTapBegan(touch) -- 2723
		if not completedRef.current then -- 2723
			____print("⏭️ [LevelIntro] 点击跳过开场动画") -- 2725
			completedRef.current = true -- 2726
			props:onComplete() -- 2727
		end -- 2727
		return true -- 2729
	end -- 2723
	local timer = timerRef.current -- 2732
	local fadeOpacity = 1 -- 2733
	if timer < 0.5 then -- 2733
		fadeOpacity = timer / 0.5 -- 2735
	elseif timer > 3 then -- 2735
		fadeOpacity = (3.5 - timer) / 0.5 -- 2737
	end -- 2737
	local snowParticles = snowParticlesRef.current -- 2740
	return React.createElement( -- 2742
		"node", -- 2742
		{onUpdate = handleUpdate, touchEnabled = true, onTapBegan = handleTapBegan, order = 2000}, -- 2742
		React.createElement( -- 2742
			"draw-node", -- 2742
			nil, -- 2742
			React.createElement("rect-shape", {width = 2000, height = 2000, fillColor = 255}) -- 2742
		), -- 2742
		React.createElement( -- 2742
			"node", -- 2742
			{opacity = fadeOpacity}, -- 2742
			__TS__ArrayMap( -- 2749
				snowParticles, -- 2749
				function(____, particle, index) return React.createElement( -- 2749
					SnowParticle, -- 2750
					{ -- 2750
						key = "snow" .. tostring(index), -- 2750
						initialX = particle.x, -- 2750
						initialY = particle.y, -- 2750
						speed = particle.speed, -- 2750
						size = particle.size -- 2750
					} -- 2750
				) end -- 2750
			) -- 2750
		), -- 2750
		React.createElement( -- 2750
			"node", -- 2750
			{y = 50, opacity = fadeOpacity}, -- 2750
			React.createElement("label", { -- 2750
				fontName = "sarasa-mono-sc-regular", -- 2750
				fontSize = 56, -- 2750
				text = props.title, -- 2750
				y = -14, -- 2750
				alignment = "Center" -- 2750
			}) -- 2750
		), -- 2750
		React.createElement( -- 2750
			"node", -- 2750
			{y = -20, opacity = fadeOpacity}, -- 2750
			React.createElement("label", { -- 2750
				fontName = "sarasa-mono-sc-regular", -- 2750
				fontSize = 32, -- 2750
				text = props.subtitle, -- 2750
				y = -8, -- 2750
				alignment = "Center" -- 2750
			}) -- 2750
		), -- 2750
		React.createElement( -- 2750
			"node", -- 2750
			{y = -280, opacity = fadeOpacity * 0.6}, -- 2750
			React.createElement("label", { -- 2750
				fontName = "sarasa-mono-sc-regular", -- 2750
				fontSize = 20, -- 2750
				text = "按空格或点击跳过", -- 2750
				y = -5, -- 2750
				alignment = "Center" -- 2750
			}) -- 2750
		) -- 2750
	) -- 2750
end -- 2679
local function SimpleDialog(props) -- 2802
	local lastSpacePressedRef = useRef(false) -- 2803
	local initRef = useRef(false) -- 2804
	local initializedDisplayRef = useRef(false) -- 2805
	local completedRef = useRef(false) -- 2806
	local currentIndexRef = useRef(0) -- 2807
	local textLabelRef = useRef(nil) -- 2808
	local nameLabelRef = useRef(nil) -- 2809
	local avatarPlayerRef = useRef(nil) -- 2810
	local avatarNpcRef = useRef(nil) -- 2811
	local nameNodeRef = useRef(nil) -- 2812
	local avatarNodeRef = useRef(nil) -- 2813
	local activationDelayRef = useRef(0) -- 2814
	local lastGameStateRef = useRef("") -- 2815
	if not initRef.current then -- 2815
		____print("💬 [SimpleDialog] 对话系统初始化") -- 2818
		initRef.current = true -- 2819
	end -- 2819
	local function updateDisplay() -- 2822
		local msg = props.messages[currentIndexRef.current] -- 2823
		if not msg then -- 2823
			return -- 2824
		end -- 2824
		local textLabel = textLabelRef.current -- 2826
		local nameLabel = nameLabelRef.current -- 2827
		local avatarPlayer = avatarPlayerRef.current -- 2828
		local avatarNpc = avatarNpcRef.current -- 2829
		local nameNode = nameNodeRef.current -- 2830
		local avatarNode = avatarNodeRef.current -- 2831
		if textLabel then -- 2831
			textLabel.text = msg.text -- 2833
		end -- 2833
		if nameLabel then -- 2833
			nameLabel.text = msg.name -- 2834
		end -- 2834
		if avatarPlayer then -- 2834
			avatarPlayer.visible = msg.speaker == "player" -- 2836
		end -- 2836
		if avatarNpc then -- 2836
			avatarNpc.visible = msg.speaker ~= "player" -- 2837
		end -- 2837
		if nameNode then -- 2837
			nameNode.x = msg.speaker == "player" and -350 or 500 -- 2839
		end -- 2839
		if avatarNode then -- 2839
			avatarNode.x = msg.speaker == "player" and -380 or 380 -- 2842
		end -- 2842
		____print((("📖 [SimpleDialog] 显示: " .. tostring(msg.name)) .. ": ") .. tostring(msg.text)) -- 2845
	end -- 2822
	local function handleNext() -- 2848
		if completedRef.current then -- 2848
			return -- 2850
		end -- 2850
		____print((("📖 [SimpleDialog] 当前索引: " .. tostring(currentIndexRef.current)) .. ", 总消息数: ") .. tostring(#props.messages)) -- 2853
		currentIndexRef.current = currentIndexRef.current + 1 -- 2855
		if currentIndexRef.current >= #props.messages then -- 2855
			____print("✅ [SimpleDialog] 对话完成") -- 2858
			completedRef.current = true -- 2859
			props:onComplete() -- 2860
		else -- 2860
			____print(("📖 [SimpleDialog] 切换到第 " .. tostring(currentIndexRef.current + 1)) .. " 句") -- 2862
			updateDisplay() -- 2863
		end -- 2863
	end -- 2848
	local function handleUpdate(deltaTime) -- 2867
		local currentGameState = props.gameStateRef.current -- 2868
		if lastGameStateRef.current ~= "dialog" and currentGameState == "dialog" then -- 2868
			____print("🔄 [SimpleDialog] 重置对话状态，开始新对话") -- 2871
			completedRef.current = false -- 2872
			currentIndexRef.current = 0 -- 2873
			initializedDisplayRef.current = false -- 2874
			activationDelayRef.current = 0 -- 2875
			lastSpacePressedRef.current = false -- 2876
		end -- 2876
		lastGameStateRef.current = currentGameState -- 2879
		if completedRef.current then -- 2879
			return false -- 2882
		end -- 2882
		if currentGameState ~= "dialog" then -- 2882
			lastSpacePressedRef.current = false -- 2886
			activationDelayRef.current = 0 -- 2887
			return false -- 2888
		end -- 2888
		if activationDelayRef.current < 0.2 then -- 2888
			activationDelayRef.current = activationDelayRef.current + deltaTime -- 2893
			return false -- 2894
		end -- 2894
		if not initializedDisplayRef.current and textLabelRef.current then -- 2894
			updateDisplay() -- 2899
			initializedDisplayRef.current = true -- 2900
			lastSpacePressedRef.current = Keyboard:isKeyPressed("Space") -- 2901
			return false -- 2902
		end -- 2902
		local spacePressed = Keyboard:isKeyPressed("Space") -- 2905
		if not lastSpacePressedRef.current and spacePressed then -- 2905
			handleNext() -- 2908
		end -- 2908
		lastSpacePressedRef.current = spacePressed -- 2911
		return false -- 2913
	end -- 2867
	local currentMsg = props.messages[currentIndexRef.current] -- 2916
	if not currentMsg then -- 2916
		currentMsg = props.messages[#props.messages] or ({speaker = "npc", name = "...", text = "..."}) -- 2918
	end -- 2918
	local isPlayer = currentMsg.speaker == "player" -- 2921
	return React.createElement( -- 2923
		"node", -- 2923
		{ -- 2923
			x = 0, -- 2923
			y = 0, -- 2923
			onUpdate = handleUpdate, -- 2923
			touchEnabled = false, -- 2923
			order = 1000, -- 2923
			scaleX = 1, -- 2923
			scaleY = 1 -- 2923
		}, -- 2923
		React.createElement( -- 2923
			"node", -- 2923
			{y = -250}, -- 2923
			React.createElement("sprite", {width = 900, height = 250, opacity = 0.9}), -- 2923
			"  ", -- 2923
			React.createElement( -- 2923
				"draw-node", -- 2923
				nil, -- 2923
				React.createElement( -- 2923
					"polygon-shape", -- 2923
					{ -- 2923
						verts = { -- 2923
							Vec2(0, -8), -- 2931
							Vec2(10, 0), -- 2932
							Vec2(0, 8) -- 2933
						}, -- 2933
						x = 420, -- 2933
						y = 100, -- 2933
						fillColor = 4294967295 -- 2933
					} -- 2933
				) -- 2933
			), -- 2933
			React.createElement( -- 2933
				"node", -- 2933
				{ref = nameNodeRef, x = isPlayer and -350 or 500, y = -95}, -- 2933
				React.createElement("sprite", {width = 200, height = 40}), -- 2933
				"  ", -- 2933
				React.createElement("label", { -- 2933
					ref = nameLabelRef, -- 2933
					fontName = "sarasa-mono-sc-regular", -- 2933
					fontSize = 24, -- 2933
					text = currentMsg.name, -- 2933
					x = -80, -- 2933
					y = -5, -- 2933
					alignment = "Center" -- 2933
				}) -- 2933
			), -- 2933
			React.createElement( -- 2933
				"node", -- 2933
				{ref = avatarNodeRef, x = isPlayer and -380 or 380, y = 0}, -- 2933
				React.createElement("sprite", { -- 2933
					ref = avatarPlayerRef, -- 2933
					file = "Image/avatar_player.png", -- 2933
					width = 120, -- 2933
					height = 120, -- 2933
					filter = "Point", -- 2933
					visible = isPlayer -- 2933
				}), -- 2933
				React.createElement("sprite", { -- 2933
					ref = avatarNpcRef, -- 2933
					file = "Image/avatar_npc.png", -- 2933
					width = 120, -- 2933
					height = 120, -- 2933
					filter = "Point", -- 2933
					visible = not isPlayer -- 2933
				}) -- 2933
			), -- 2933
			React.createElement( -- 2933
				"node", -- 2933
				{x = 0, y = 0}, -- 2933
				React.createElement("label", { -- 2933
					ref = textLabelRef, -- 2933
					fontName = "sarasa-mono-sc-regular", -- 2933
					fontSize = 28, -- 2933
					text = currentMsg.text, -- 2933
					width = 600, -- 2933
					height = 120, -- 2933
					x = 0, -- 2933
					y = 20, -- 2933
					alignment = "Center" -- 2933
				}) -- 2933
			), -- 2933
			React.createElement( -- 2933
				"node", -- 2933
				{y = -140}, -- 2933
				React.createElement( -- 2933
					"draw-node", -- 2933
					nil, -- 2933
					__TS__ArrayMap( -- 2990
						props.messages, -- 2990
						function(____, _, index) -- 2990
							local radius = 4 -- 2991
							local color = index <= currentIndexRef.current and 4294967295 or 1717986918 -- 2992
							local spacing = 18 -- 2993
							local startX = -(#props.messages - 1) * spacing / 2 -- 2994
							local centerX = startX + index * spacing -- 2995
							local points = {} -- 2997
							do -- 2997
								local i = 0 -- 2998
								while i < 16 do -- 2998
									local angle = i / 16 * math.pi * 2 -- 2999
									points[#points + 1] = Vec2( -- 3000
										math.cos(angle) * radius + centerX, -- 3001
										math.sin(angle) * radius -- 3002
									) -- 3002
									i = i + 1 -- 2998
								end -- 2998
							end -- 2998
							return React.createElement( -- 3006
								"polygon-shape", -- 3006
								{ -- 3006
									key = "dot" .. tostring(index), -- 3006
									verts = points, -- 3006
									fillColor = color -- 3006
								} -- 3006
							) -- 3006
						end -- 2990
					) -- 2990
				) -- 2990
			), -- 2990
			React.createElement( -- 2990
				"node", -- 2990
				{y = -100}, -- 2990
				React.createElement("label", { -- 2990
					fontName = "sarasa-mono-sc-regular", -- 2990
					fontSize = 18, -- 2990
					text = "按空格继续", -- 2990
					alignment = "Center", -- 2990
					opacity = 0.7 -- 2990
				}) -- 2990
			) -- 2990
		) -- 2990
	) -- 2990
end -- 2802
local function startGame(levelIndex) -- 3034
	____print("🎮 开始关卡") -- 3035
	currentLevel = levelIndex -- 3036
	playerPosition = {x = LEVELS[currentLevel + 1].playerStart.x, y = LEVELS[currentLevel + 1].playerStart.y} -- 3037
	local entry = Director.entry -- 3042
	if entry then -- 3042
		entry:removeAllChildren() -- 3044
		entry:addChild(toNode(React.createElement( -- 3047
			ScaledRoot, -- 3048
			nil, -- 3048
			React.createElement(Game, nil) -- 3048
		))) -- 3048
	end -- 3048
end -- 3034
local function LevelIntroScene(props) -- 3056
	local completedRef = useRef(false) -- 3057
	local function handleIntroComplete() -- 3059
		if completedRef.current then -- 3059
			return -- 3060
		end -- 3060
		completedRef.current = true -- 3061
		____print("🎬 [LevelIntroScene] 开场动画完成，进入游戏") -- 3063
		local entry = Director.entry -- 3064
		if entry then -- 3064
			entry:removeAllChildren() -- 3066
			entry:addChild(toNode(React.createElement( -- 3067
				ScaledRoot, -- 3068
				nil, -- 3068
				React.createElement(Game, nil) -- 3068
			))) -- 3068
		end -- 3068
	end -- 3059
	local level = LEVELS[props.levelIndex + 1] -- 3075
	return React.createElement(LevelIntro, {title = level.intro.title, subtitle = level.intro.subtitle, onComplete = handleIntroComplete}) -- 3077
end -- 3056
local function returnToMenu() -- 3086
	____print("📋 返回主菜单") -- 3087
	local entry = Director.entry -- 3088
	if entry then -- 3088
		entry:removeAllChildren() -- 3090
		entry:addChild(toNode(React.createElement( -- 3091
			ScaledRoot, -- 3092
			nil, -- 3092
			React.createElement(MainMenu, nil) -- 3092
		))) -- 3092
	end -- 3092
end -- 3086
MainMenu = function() -- 3102
	local difficultyLabelRef = useRef(nil) -- 3103
	local bgmStartedRef = useRef(false) -- 3104
	local confirmDialogRef = useRef(nil) -- 3105
	local showConfirmRef = useRef(false) -- 3106
	if not bgmStartedRef.current then -- 3106
		playBGM(SOUND_FILES.bgm_menu, 0.4) -- 3110
		bgmStartedRef.current = true -- 3111
	end -- 3111
	local function handleMenuTap(touch) -- 3114
		local loc = touch.location -- 3115
		local clickX = loc.x -- 3116
		local clickY = loc.y -- 3117
		____print(((("🖱️ [主菜单] 点击位置: (" .. tostring(clickX)) .. ", ") .. tostring(clickY)) .. ")") -- 3119
		if showConfirmRef.current then -- 3119
			if clickX >= -120 and clickX <= -20 and clickY >= -100 and clickY <= -40 then -- 3119
				____print("✅ [主菜单] 确认清空存档") -- 3125
				clearSave() -- 3126
				showConfirmRef.current = false -- 3127
				local dialog = confirmDialogRef.current -- 3128
				if dialog then -- 3128
					dialog.visible = false -- 3129
				end -- 3129
				return true -- 3130
			end -- 3130
			if clickX >= 20 and clickX <= 120 and clickY >= -100 and clickY <= -40 then -- 3130
				____print("❌ [主菜单] 取消清空存档") -- 3134
				showConfirmRef.current = false -- 3135
				local dialog = confirmDialogRef.current -- 3136
				if dialog then -- 3136
					dialog.visible = false -- 3137
				end -- 3137
				return true -- 3138
			end -- 3138
			return true -- 3140
		end -- 3140
		local BTN_X = -500 -- 3144
		local BTN_HALF_W = 140 -- 3145
		local BTN_HALF_H = 35 -- 3146
		if clickX >= BTN_X - BTN_HALF_W and clickX <= BTN_X + BTN_HALF_W and clickY >= 60 - BTN_HALF_H and clickY <= 60 + BTN_HALF_H then -- 3146
			____print("✅ [主菜单] 点击了选关") -- 3153
			local entry = Director.entry -- 3154
			if entry then -- 3154
				entry:removeAllChildren() -- 3156
				entry:addChild(toNode(React.createElement( -- 3157
					ScaledRoot, -- 3158
					nil, -- 3158
					React.createElement(LevelSelectMenu, nil) -- 3158
				))) -- 3158
			end -- 3158
			return true -- 3163
		end -- 3163
		if clickX >= BTN_X - BTN_HALF_W and clickX <= BTN_X + BTN_HALF_W and clickY >= -20 - BTN_HALF_H and clickY <= -20 + BTN_HALF_H then -- 3163
			____print("🎬 [主菜单] 点击了查看结局") -- 3171
			local entry = Director.entry -- 3172
			if entry then -- 3172
				entry:removeAllChildren() -- 3174
				entry:addChild(toNode(React.createElement( -- 3175
					ScaledRoot, -- 3176
					nil, -- 3176
					React.createElement(EndingGallery, nil) -- 3176
				))) -- 3176
			end -- 3176
			return true -- 3181
		end -- 3181
		if clickX >= BTN_X - BTN_HALF_W - 100 and clickX <= BTN_X + BTN_HALF_W + 100 and clickY >= -100 - BTN_HALF_H and clickY <= -100 + BTN_HALF_H then -- 3181
			____print("🎮 [主菜单] 点击了难度选择") -- 3189
			cycleDifficulty() -- 3190
			local label = difficultyLabelRef.current -- 3192
			if label then -- 3192
				label.text = ((("难度: " .. getDifficultyName()) .. " (冲刺cd：") .. tostring(SPRINT_COOLDOWN)) .. "秒)" -- 3194
			end -- 3194
			return true -- 3196
		end -- 3196
		if clickX >= BTN_X - BTN_HALF_W and clickX <= BTN_X + BTN_HALF_W and clickY >= -180 - BTN_HALF_H and clickY <= -180 + BTN_HALF_H then -- 3196
			____print("🗑️ [主菜单] 点击了清空存档，显示确认对话框") -- 3204
			showConfirmRef.current = true -- 3205
			local dialog = confirmDialogRef.current -- 3206
			if dialog then -- 3206
				dialog.visible = true -- 3207
			end -- 3207
			return true -- 3208
		end -- 3208
		if clickX >= BTN_X - BTN_HALF_W and clickX <= BTN_X + BTN_HALF_W and clickY >= -260 - BTN_HALF_H and clickY <= -260 + BTN_HALF_H then -- 3208
			____print("👋 [主菜单] 退出游戏") -- 3216
			App:shutdown() -- 3217
			return true -- 3218
		end -- 3218
		____print("❌ [主菜单] 没有点击到任何按钮") -- 3221
		return false -- 3222
	end -- 3114
	return React.createElement( -- 3225
		"node", -- 3225
		{touchEnabled = true, onTapBegan = handleMenuTap}, -- 3225
		React.createElement("sprite", {file = "Image/GameStart.png", width = 1950, height = 1100}), -- 3225
		"  ", -- 3225
		React.createElement( -- 3225
			"draw-node", -- 3225
			nil, -- 3225
			React.createElement("rect-shape", {width = 2000, height = 2000, fillColor = 1}) -- 3225
		), -- 3225
		React.createElement( -- 3225
			"node", -- 3225
			{x = -500, y = 60}, -- 3225
			React.createElement("sprite", {width = 280, height = 70, filter = "Point"}), -- 3225
			React.createElement("label", { -- 3225
				fontName = "sarasa-mono-sc-regular", -- 3225
				fontSize = 36, -- 3225
				text = "选关", -- 3225
				y = -9, -- 3225
				alignment = "Center" -- 3225
			}) -- 3225
		), -- 3225
		React.createElement( -- 3225
			"node", -- 3225
			{x = -500, y = -20}, -- 3225
			React.createElement("sprite", {width = 280, height = 70, filter = "Point"}), -- 3225
			React.createElement( -- 3225
				"label", -- 3225
				{ -- 3225
					fontName = "sarasa-mono-sc-regular", -- 3225
					fontSize = 36, -- 3225
					text = ("结局 (" .. tostring(getUnlockedEndingsCount())) .. "/3)", -- 3225
					y = -9, -- 3225
					alignment = "Center" -- 3225
				} -- 3225
			) -- 3225
		), -- 3225
		React.createElement( -- 3225
			"node", -- 3225
			{x = -500, y = -100}, -- 3225
			React.createElement("sprite", {width = 480, height = 70, filter = "Point"}), -- 3225
			React.createElement( -- 3225
				"label", -- 3225
				{ -- 3225
					ref = difficultyLabelRef, -- 3225
					fontName = "sarasa-mono-sc-regular", -- 3225
					fontSize = 32, -- 3225
					text = ((("难度: " .. getDifficultyName()) .. " (冲刺cd：") .. tostring(SPRINT_COOLDOWN)) .. "秒)", -- 3225
					y = -8, -- 3225
					alignment = "Center" -- 3225
				} -- 3225
			) -- 3225
		), -- 3225
		React.createElement( -- 3225
			"node", -- 3225
			{x = -500, y = -180}, -- 3225
			React.createElement("sprite", {width = 280, height = 70, filter = "Point"}), -- 3225
			React.createElement("label", { -- 3225
				fontName = "sarasa-mono-sc-regular", -- 3225
				fontSize = 36, -- 3225
				text = "清空存档", -- 3225
				y = -9, -- 3225
				alignment = "Center" -- 3225
			}) -- 3225
		), -- 3225
		React.createElement( -- 3225
			"node", -- 3225
			{x = -500, y = -260}, -- 3225
			React.createElement("sprite", {width = 280, height = 70, filter = "Point"}), -- 3225
			React.createElement("label", { -- 3225
				fontName = "sarasa-mono-sc-regular", -- 3225
				fontSize = 36, -- 3225
				text = "退出", -- 3225
				y = -9, -- 3225
				alignment = "Center" -- 3225
			}) -- 3225
		), -- 3225
		React.createElement( -- 3225
			"node", -- 3225
			{ref = confirmDialogRef, visible = false, order = 100}, -- 3225
			React.createElement( -- 3225
				"draw-node", -- 3225
				nil, -- 3225
				React.createElement("rect-shape", {width = 2000, height = 2000, fillColor = 204}) -- 3225
			), -- 3225
			React.createElement( -- 3225
				"node", -- 3225
				{y = 50}, -- 3225
				React.createElement("label", {fontName = "sarasa-mono-sc-regular", fontSize = 36, text = "确定要清空存档吗？", alignment = "Center"}) -- 3225
			), -- 3225
			React.createElement( -- 3225
				"node", -- 3225
				{y = 0}, -- 3225
				React.createElement("label", { -- 3225
					fontName = "sarasa-mono-sc-regular", -- 3225
					fontSize = 24, -- 3225
					text = "所有进度将被删除", -- 3225
					alignment = "Center", -- 3225
					opacity = 0.7 -- 3225
				}) -- 3225
			), -- 3225
			React.createElement( -- 3225
				"node", -- 3225
				{x = -70, y = -70}, -- 3225
				React.createElement("sprite", {width = 100, height = 50, filter = "Point"}), -- 3225
				React.createElement("label", { -- 3225
					fontName = "sarasa-mono-sc-regular", -- 3225
					fontSize = 28, -- 3225
					text = "确定", -- 3225
					y = -7, -- 3225
					alignment = "Center" -- 3225
				}) -- 3225
			), -- 3225
			React.createElement( -- 3225
				"node", -- 3225
				{x = 70, y = -70}, -- 3225
				React.createElement("sprite", {width = 100, height = 50, filter = "Point"}), -- 3225
				React.createElement("label", { -- 3225
					fontName = "sarasa-mono-sc-regular", -- 3225
					fontSize = 28, -- 3225
					text = "取消", -- 3225
					y = -7, -- 3225
					alignment = "Center" -- 3225
				}) -- 3225
			) -- 3225
		) -- 3225
	) -- 3225
end -- 3102
local ENDING_IMAGES = {fake = { -- 3300
	"Image/cg/LostEnding-1.png", -- 3302
	"Image/cg/LostEnding-2.png", -- 3302
	"Image/cg/LostEnding-3.png", -- 3302
	"Image/cg/LostEnding-4.png", -- 3302
	"Image/cg/LostEnding-5.png", -- 3303
	"Image/cg/LostEnding-6.png", -- 3303
	"Image/cg/LostEnding-7.png", -- 3303
	"Image/cg/LostEnding-8.png" -- 3303
}, sacrifice = { -- 3303
	"Image/cg/SacrificeEnding-1.png", -- 3306
	"Image/cg/SacrificeEnding-2.png", -- 3306
	"Image/cg/SacrificeEnding-3.png", -- 3306
	"Image/cg/SacrificeEnding-4.png", -- 3306
	"Image/cg/SacrificeEnding-5.png", -- 3307
	"Image/cg/SacrificeEnding-6.png", -- 3307
	"Image/cg/SacrificeEnding-7.png", -- 3307
	"Image/cg/SacrificeEnding-8.png" -- 3307
}, perfect = { -- 3307
	"Image/cg/TrueEnding-1.png", -- 3310
	"Image/cg/TrueEnding-2.png", -- 3310
	"Image/cg/TrueEnding-3.png", -- 3310
	"Image/cg/TrueEnding-4.png", -- 3310
	"Image/cg/TrueEnding-5.png", -- 3311
	"Image/cg/TrueEnding-6.png", -- 3311
	"Image/cg/TrueEnding-7.png", -- 3311
	"Image/cg/TrueEnding-8.png" -- 3311
}} -- 3311
EndingGallery = function() -- 3315
	local viewingEndingRef = useRef(nil) -- 3316
	local imageIndexRef = useRef(0) -- 3317
	local lastSpacePressedRef = useRef(false) -- 3318
	local imageNodeRef = useRef(nil) -- 3319
	local pageHintRef = useRef(nil) -- 3320
	local fakeSprite0Ref = useRef(nil) -- 3323
	local fakeSprite1Ref = useRef(nil) -- 3324
	local fakeSprite2Ref = useRef(nil) -- 3325
	local fakeSprite3Ref = useRef(nil) -- 3326
	local fakeSprite4Ref = useRef(nil) -- 3327
	local fakeSprite5Ref = useRef(nil) -- 3328
	local fakeSprite6Ref = useRef(nil) -- 3329
	local fakeSprite7Ref = useRef(nil) -- 3330
	local sacrificeSprite0Ref = useRef(nil) -- 3332
	local sacrificeSprite1Ref = useRef(nil) -- 3333
	local sacrificeSprite2Ref = useRef(nil) -- 3334
	local sacrificeSprite3Ref = useRef(nil) -- 3335
	local sacrificeSprite4Ref = useRef(nil) -- 3336
	local sacrificeSprite5Ref = useRef(nil) -- 3337
	local sacrificeSprite6Ref = useRef(nil) -- 3338
	local sacrificeSprite7Ref = useRef(nil) -- 3339
	local perfectSprite0Ref = useRef(nil) -- 3341
	local perfectSprite1Ref = useRef(nil) -- 3342
	local perfectSprite2Ref = useRef(nil) -- 3343
	local perfectSprite3Ref = useRef(nil) -- 3344
	local perfectSprite4Ref = useRef(nil) -- 3345
	local perfectSprite5Ref = useRef(nil) -- 3346
	local perfectSprite6Ref = useRef(nil) -- 3347
	local perfectSprite7Ref = useRef(nil) -- 3348
	local function getAllSpriteRefs() -- 3350
		return { -- 3350
			fakeSprite0Ref, -- 3351
			fakeSprite1Ref, -- 3351
			fakeSprite2Ref, -- 3351
			fakeSprite3Ref, -- 3351
			fakeSprite4Ref, -- 3351
			fakeSprite5Ref, -- 3351
			fakeSprite6Ref, -- 3351
			fakeSprite7Ref, -- 3351
			sacrificeSprite0Ref, -- 3352
			sacrificeSprite1Ref, -- 3352
			sacrificeSprite2Ref, -- 3352
			sacrificeSprite3Ref, -- 3352
			sacrificeSprite4Ref, -- 3352
			sacrificeSprite5Ref, -- 3352
			sacrificeSprite6Ref, -- 3352
			sacrificeSprite7Ref, -- 3352
			perfectSprite0Ref, -- 3353
			perfectSprite1Ref, -- 3353
			perfectSprite2Ref, -- 3353
			perfectSprite3Ref, -- 3353
			perfectSprite4Ref, -- 3353
			perfectSprite5Ref, -- 3353
			perfectSprite6Ref, -- 3353
			perfectSprite7Ref -- 3353
		} -- 3353
	end -- 3350
	local function getSpriteRef(ending, index) -- 3356
		local fakeRefs = { -- 3357
			fakeSprite0Ref, -- 3357
			fakeSprite1Ref, -- 3357
			fakeSprite2Ref, -- 3357
			fakeSprite3Ref, -- 3357
			fakeSprite4Ref, -- 3357
			fakeSprite5Ref, -- 3357
			fakeSprite6Ref, -- 3357
			fakeSprite7Ref -- 3357
		} -- 3357
		local sacrificeRefs = { -- 3358
			sacrificeSprite0Ref, -- 3358
			sacrificeSprite1Ref, -- 3358
			sacrificeSprite2Ref, -- 3358
			sacrificeSprite3Ref, -- 3358
			sacrificeSprite4Ref, -- 3358
			sacrificeSprite5Ref, -- 3358
			sacrificeSprite6Ref, -- 3358
			sacrificeSprite7Ref -- 3358
		} -- 3358
		local perfectRefs = { -- 3359
			perfectSprite0Ref, -- 3359
			perfectSprite1Ref, -- 3359
			perfectSprite2Ref, -- 3359
			perfectSprite3Ref, -- 3359
			perfectSprite4Ref, -- 3359
			perfectSprite5Ref, -- 3359
			perfectSprite6Ref, -- 3359
			perfectSprite7Ref -- 3359
		} -- 3359
		if ending == "fake" and index < 8 then -- 3359
			return fakeRefs[index + 1] -- 3361
		end -- 3361
		if ending == "sacrifice" and index < 8 then -- 3361
			return sacrificeRefs[index + 1] -- 3362
		end -- 3362
		if ending == "perfect" and index < 8 then -- 3362
			return perfectRefs[index + 1] -- 3363
		end -- 3363
		return nil -- 3364
	end -- 3356
	local function hideAllSprites() -- 3367
		__TS__ArrayForEach( -- 3368
			getAllSpriteRefs(), -- 3368
			function(____, ref) -- 3368
				if ref.current then -- 3368
					ref.current.visible = false -- 3369
				end -- 3369
			end -- 3368
		) -- 3368
	end -- 3367
	local function showCurrentSprite() -- 3373
		hideAllSprites() -- 3374
		local ending = viewingEndingRef.current -- 3375
		if not ending then -- 3375
			return -- 3376
		end -- 3376
		local spriteRef = getSpriteRef(ending, imageIndexRef.current) -- 3378
		if spriteRef and spriteRef.current then -- 3378
			spriteRef.current.visible = true -- 3380
		end -- 3380
		local pageHint = pageHintRef.current -- 3383
		if pageHint then -- 3383
			pageHint.text = tostring(imageIndexRef.current + 1) .. " / 8" -- 3385
		end -- 3385
	end -- 3373
	local function handleTap(touch) -- 3389
		local loc = touch.location -- 3390
		local clickX = loc.x -- 3391
		local clickY = loc.y -- 3392
		if viewingEndingRef.current then -- 3392
			imageIndexRef.current = imageIndexRef.current + 1 -- 3396
			if imageIndexRef.current >= 8 then -- 3396
				viewingEndingRef.current = nil -- 3399
				imageIndexRef.current = 0 -- 3400
				hideAllSprites() -- 3401
				local imageNode = imageNodeRef.current -- 3402
				if imageNode then -- 3402
					imageNode.visible = false -- 3403
				end -- 3403
			else -- 3403
				showCurrentSprite() -- 3405
			end -- 3405
			return true -- 3407
		end -- 3407
		____print(((("🖱️ [结局画廊] 点击位置: (" .. tostring(clickX)) .. ", ") .. tostring(clickY)) .. ")") -- 3410
		local Y_POS = 50 -- 3412
		if clickX >= -250 and clickX <= -50 and clickY >= Y_POS - 75 and clickY <= Y_POS + 75 then -- 3412
			if unlockedEndings.fake then -- 3412
				____print("🎬 [结局画廊] 查看假结局") -- 3417
				viewingEndingRef.current = "fake" -- 3418
				imageIndexRef.current = 0 -- 3419
				local imageNode = imageNodeRef.current -- 3420
				if imageNode then -- 3420
					imageNode.visible = true -- 3421
				end -- 3421
				showCurrentSprite() -- 3422
			end -- 3422
			return true -- 3424
		end -- 3424
		if clickX >= -100 and clickX <= 100 and clickY >= Y_POS - 75 and clickY <= Y_POS + 75 then -- 3424
			if unlockedEndings.sacrifice then -- 3424
				____print("🎬 [结局画廊] 查看牺牲结局") -- 3430
				viewingEndingRef.current = "sacrifice" -- 3431
				imageIndexRef.current = 0 -- 3432
				local imageNode = imageNodeRef.current -- 3433
				if imageNode then -- 3433
					imageNode.visible = true -- 3434
				end -- 3434
				showCurrentSprite() -- 3435
			end -- 3435
			return true -- 3437
		end -- 3437
		if clickX >= 50 and clickX <= 250 and clickY >= Y_POS - 75 and clickY <= Y_POS + 75 then -- 3437
			if unlockedEndings.perfect then -- 3437
				____print("🎬 [结局画廊] 查看完美结局") -- 3443
				viewingEndingRef.current = "perfect" -- 3444
				imageIndexRef.current = 0 -- 3445
				local imageNode = imageNodeRef.current -- 3446
				if imageNode then -- 3446
					imageNode.visible = true -- 3447
				end -- 3447
				showCurrentSprite() -- 3448
			end -- 3448
			return true -- 3450
		end -- 3450
		if clickX >= -100 and clickX <= 100 and clickY >= -150 and clickY <= -90 then -- 3450
			____print("🔙 [结局画廊] 返回主菜单") -- 3455
			returnToMenu() -- 3456
			return true -- 3457
		end -- 3457
		return false -- 3460
	end -- 3389
	local function handleUpdate(deltaTime) -- 3463
		if viewingEndingRef.current then -- 3463
			local spacePressed = Keyboard:isKeyPressed("Space") -- 3466
			local spaceDown = not lastSpacePressedRef.current and spacePressed -- 3467
			lastSpacePressedRef.current = spacePressed -- 3468
			if spaceDown then -- 3468
				imageIndexRef.current = imageIndexRef.current + 1 -- 3471
				if imageIndexRef.current >= 8 then -- 3471
					viewingEndingRef.current = nil -- 3475
					imageIndexRef.current = 0 -- 3476
					hideAllSprites() -- 3477
					local imageNode = imageNodeRef.current -- 3478
					if imageNode then -- 3478
						imageNode.visible = false -- 3479
					end -- 3479
				else -- 3479
					showCurrentSprite() -- 3481
				end -- 3481
			end -- 3481
		else -- 3481
			lastSpacePressedRef.current = Keyboard:isKeyPressed("Space") -- 3485
		end -- 3485
		return false -- 3488
	end -- 3463
	return React.createElement( -- 3491
		"node", -- 3491
		{touchEnabled = true, onTapBegan = handleTap, onUpdate = handleUpdate}, -- 3491
		React.createElement("sprite", {file = "Image/menu_bg.png", width = 1950, height = 1100}), -- 3491
		"  ", -- 3491
		React.createElement( -- 3491
			"draw-node", -- 3491
			nil, -- 3491
			React.createElement("rect-shape", {width = 2000, height = 2000, fillColor = 1}) -- 3491
		), -- 3491
		React.createElement( -- 3491
			"node", -- 3491
			{y = 200}, -- 3491
			React.createElement("label", { -- 3491
				fontName = "sarasa-mono-sc-regular", -- 3491
				fontSize = 40, -- 3491
				text = "结局画廊", -- 3491
				y = -10, -- 3491
				alignment = "Center" -- 3491
			}) -- 3491
		), -- 3491
		React.createElement( -- 3491
			"node", -- 3491
			{x = -150, y = 50}, -- 3491
			React.createElement("sprite", {width = 200, height = 150, filter = "Point", opacity = unlockedEndings.fake and 1 or 0.3}), -- 3491
			React.createElement("label", { -- 3491
				fontName = "sarasa-mono-sc-regular", -- 3491
				fontSize = 24, -- 3491
				text = unlockedEndings.fake and "谎言" or "???", -- 3491
				y = -6, -- 3491
				alignment = "Center" -- 3491
			}) -- 3491
		), -- 3491
		React.createElement( -- 3491
			"node", -- 3491
			{x = 0, y = 50}, -- 3491
			React.createElement("sprite", {width = 200, height = 150, filter = "Point", opacity = unlockedEndings.sacrifice and 1 or 0.3}), -- 3491
			React.createElement("label", { -- 3491
				fontName = "sarasa-mono-sc-regular", -- 3491
				fontSize = 24, -- 3491
				text = unlockedEndings.sacrifice and "交换" or "???", -- 3491
				y = -6, -- 3491
				alignment = "Center" -- 3491
			}) -- 3491
		), -- 3491
		React.createElement( -- 3491
			"node", -- 3491
			{x = 150, y = 50}, -- 3491
			React.createElement("sprite", {width = 200, height = 150, filter = "Point", opacity = unlockedEndings.perfect and 1 or 0.3}), -- 3491
			React.createElement("label", { -- 3491
				fontName = "sarasa-mono-sc-regular", -- 3491
				fontSize = 24, -- 3491
				text = unlockedEndings.perfect and "回家" or "???", -- 3491
				y = -6, -- 3491
				alignment = "Center" -- 3491
			}) -- 3491
		), -- 3491
		React.createElement( -- 3491
			"node", -- 3491
			{y = -120}, -- 3491
			React.createElement("sprite", {width = 200, height = 60, filter = "Point"}), -- 3491
			"  ", -- 3491
			React.createElement("label", { -- 3491
				fontName = "sarasa-mono-sc-regular", -- 3491
				fontSize = 28, -- 3491
				text = "返回", -- 3491
				y = -7, -- 3491
				alignment = "Center" -- 3491
			}) -- 3491
		), -- 3491
		React.createElement( -- 3491
			"node", -- 3491
			{ref = imageNodeRef, visible = false, order = 100}, -- 3491
			React.createElement( -- 3491
				"draw-node", -- 3491
				nil, -- 3491
				React.createElement("rect-shape", {width = 2000, height = 2000, fillColor = 221}) -- 3491
			), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite0Ref, -- 3491
				file = ENDING_IMAGES.fake[1], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite1Ref, -- 3491
				file = ENDING_IMAGES.fake[2], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite2Ref, -- 3491
				file = ENDING_IMAGES.fake[3], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite3Ref, -- 3491
				file = ENDING_IMAGES.fake[4], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite4Ref, -- 3491
				file = ENDING_IMAGES.fake[5], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite5Ref, -- 3491
				file = ENDING_IMAGES.fake[6], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite6Ref, -- 3491
				file = ENDING_IMAGES.fake[7], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = fakeSprite7Ref, -- 3491
				file = ENDING_IMAGES.fake[8], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite0Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[1], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite1Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[2], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite2Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[3], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite3Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[4], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite4Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[5], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite5Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[6], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite6Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[7], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = sacrificeSprite7Ref, -- 3491
				file = ENDING_IMAGES.sacrifice[8], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite0Ref, -- 3491
				file = ENDING_IMAGES.perfect[1], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite1Ref, -- 3491
				file = ENDING_IMAGES.perfect[2], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite2Ref, -- 3491
				file = ENDING_IMAGES.perfect[3], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite3Ref, -- 3491
				file = ENDING_IMAGES.perfect[4], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite4Ref, -- 3491
				file = ENDING_IMAGES.perfect[5], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite5Ref, -- 3491
				file = ENDING_IMAGES.perfect[6], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite6Ref, -- 3491
				file = ENDING_IMAGES.perfect[7], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement("sprite", { -- 3491
				ref = perfectSprite7Ref, -- 3491
				file = ENDING_IMAGES.perfect[8], -- 3491
				width = 1000, -- 3491
				height = 1000, -- 3491
				filter = "Point", -- 3491
				visible = false -- 3491
			}), -- 3491
			React.createElement( -- 3491
				"node", -- 3491
				{y = -350}, -- 3491
				React.createElement("label", { -- 3491
					ref = pageHintRef, -- 3491
					fontName = "sarasa-mono-sc-regular", -- 3491
					fontSize = 20, -- 3491
					text = "1 / 8", -- 3491
					alignment = "Center", -- 3491
					opacity = 0.7 -- 3491
				}) -- 3491
			), -- 3491
			React.createElement( -- 3491
				"node", -- 3491
				{y = -380}, -- 3491
				React.createElement("label", { -- 3491
					fontName = "sarasa-mono-sc-regular", -- 3491
					fontSize = 18, -- 3491
					text = "按空格或点击继续", -- 3491
					alignment = "Center", -- 3491
					opacity = 0.5 -- 3491
				}) -- 3491
			) -- 3491
		) -- 3491
	) -- 3491
end -- 3315
LevelSelectMenu = function() -- 3622
	local selectedLevelRef = useRef(nil) -- 3623
	local function handleUpdate(deltaTime) -- 3625
		local selectedLevel = selectedLevelRef.current -- 3626
		if selectedLevel ~= nil then -- 3626
			selectedLevelRef.current = nil -- 3628
			startGame(selectedLevel) -- 3629
		end -- 3629
		return false -- 3631
	end -- 3625
	local function handleMenuTap(touch) -- 3634
		local loc = touch.location -- 3635
		local clickX = loc.x -- 3636
		local clickY = loc.y -- 3637
		____print(((("🖱️ [选关菜单] 点击位置: (" .. tostring(clickX)) .. ", ") .. tostring(clickY)) .. ")") -- 3639
		local BTN_SIZE = 120 -- 3641
		local BTN_HALF = 60 -- 3642
		local TOP_ROW_Y = 120 -- 3643
		local BOTTOM_ROW_Y = -40 -- 3644
		local X_POSITIONS = {-225, -75, 75, 225} -- 3645
		if clickY >= TOP_ROW_Y - BTN_HALF and clickY <= TOP_ROW_Y + BTN_HALF then -- 3645
			do -- 3645
				local col = 0 -- 3648
				while col < 4 do -- 3648
					local btnX = X_POSITIONS[col + 1] -- 3649
					local levelIndex = col -- 3650
					if clickX >= btnX - BTN_HALF and clickX <= btnX + BTN_HALF and levelIndex < #LEVELS then -- 3650
						if LEVELS[levelIndex + 1].hidden then -- 3650
							return true -- 3659
						end -- 3659
						if not isLevelUnlocked(levelIndex) then -- 3659
							____print(("🔒 [选关菜单] 第 " .. tostring(levelIndex + 1)) .. " 关尚未解锁") -- 3663
							return true -- 3664
						end -- 3664
						____print(("✅ [选关菜单] 选择了第 " .. tostring(levelIndex + 1)) .. " 关") -- 3667
						selectedLevelRef.current = levelIndex -- 3668
						return true -- 3669
					end -- 3669
					col = col + 1 -- 3648
				end -- 3648
			end -- 3648
		end -- 3648
		if clickY >= BOTTOM_ROW_Y - BTN_HALF and clickY <= BOTTOM_ROW_Y + BTN_HALF then -- 3648
			do -- 3648
				local col = 0 -- 3675
				while col < 4 do -- 3675
					local btnX = X_POSITIONS[col + 1] -- 3676
					local levelIndex = col + 4 -- 3677
					if clickX >= btnX - BTN_HALF and clickX <= btnX + BTN_HALF then -- 3677
						if col == 3 then -- 3677
							____print("🔙 [选关菜单] 返回主菜单") -- 3684
							returnToMenu() -- 3685
							return true -- 3686
						end -- 3686
						if levelIndex < #LEVELS then -- 3686
							if LEVELS[levelIndex + 1].hidden then -- 3686
								return true -- 3692
							end -- 3692
							if not isLevelUnlocked(levelIndex) then -- 3692
								____print(("🔒 [选关菜单] 第 " .. tostring(levelIndex + 1)) .. " 关尚未解锁") -- 3696
								return true -- 3697
							end -- 3697
							____print(("✅ [选关菜单] 选择了第 " .. tostring(levelIndex + 1)) .. " 关") -- 3700
							selectedLevelRef.current = levelIndex -- 3701
							return true -- 3702
						end -- 3702
					end -- 3702
					col = col + 1 -- 3675
				end -- 3675
			end -- 3675
		end -- 3675
		____print("❌ [选关菜单] 没有点击到任何按钮") -- 3708
		return false -- 3709
	end -- 3634
	local function renderLevelButton(index, x, y) -- 3712
		if LEVELS[index + 1] and LEVELS[index + 1].hidden then -- 3712
			return nil -- 3715
		end -- 3715
		local isUnlocked = isLevelUnlocked(index) -- 3718
		return React.createElement( -- 3720
			"node", -- 3720
			{ -- 3720
				key = "btn" .. tostring(index), -- 3720
				x = x, -- 3720
				y = y -- 3720
			}, -- 3720
			React.createElement( -- 3720
				"label", -- 3720
				{ -- 3720
					fontName = "sarasa-mono-sc-regular", -- 3720
					fontSize = 36, -- 3720
					text = isUnlocked and tostring(index + 1) or "🔒", -- 3720
					y = -9, -- 3720
					alignment = "Center", -- 3720
					opacity = isUnlocked and 1 or 0.5 -- 3720
				} -- 3720
			) -- 3720
		) -- 3720
	end -- 3712
	local function renderBackButton(x, y) -- 3734
		return React.createElement( -- 3735
			"node", -- 3735
			{key = "btnBack", x = x, y = y}, -- 3735
			React.createElement("label", { -- 3735
				fontName = "sarasa-mono-sc-regular", -- 3735
				fontSize = 36, -- 3735
				text = "返回", -- 3735
				y = -9, -- 3735
				alignment = "Center" -- 3735
			}) -- 3735
		) -- 3735
	end -- 3734
	local TOP_ROW_Y = 120 -- 3748
	local BOTTOM_ROW_Y = -40 -- 3749
	local X_POSITIONS = {-225, -75, 75, 225} -- 3750
	return React.createElement( -- 3752
		"node", -- 3752
		{onUpdate = handleUpdate, touchEnabled = true, onTapBegan = handleMenuTap}, -- 3752
		React.createElement("sprite", {file = "Image/menu_bg.png", width = 1950, height = 1100}), -- 3752
		"  ", -- 3752
		React.createElement( -- 3752
			"draw-node", -- 3752
			nil, -- 3752
			React.createElement("rect-shape", {width = 2000, height = 2000, fillColor = 1}) -- 3752
		), -- 3752
		__TS__ArrayMap( -- 3760
			{0, 1, 2, 3}, -- 3760
			function(____, col) -- 3760
				local levelIndex = col -- 3761
				if levelIndex < #LEVELS then -- 3761
					return renderLevelButton(levelIndex, X_POSITIONS[col + 1], TOP_ROW_Y) -- 3763
				end -- 3763
				return nil -- 3765
			end -- 3760
		), -- 3760
		__TS__ArrayMap( -- 3768
			{0, 1, 2, 3}, -- 3768
			function(____, col) -- 3768
				local levelIndex = col + 4 -- 3769
				if col == 3 then -- 3769
					return renderBackButton(X_POSITIONS[col + 1], BOTTOM_ROW_Y) -- 3772
				end -- 3772
				if levelIndex < #LEVELS then -- 3772
					return renderLevelButton(levelIndex, X_POSITIONS[col + 1], BOTTOM_ROW_Y) -- 3776
				end -- 3776
				return nil -- 3779
			end -- 3768
		), -- 3768
		React.createElement( -- 3768
			"node", -- 3768
			{y = -150}, -- 3768
			React.createElement( -- 3768
				"label", -- 3768
				{ -- 3768
					fontName = "sarasa-mono-sc-regular", -- 3768
					fontSize = 24, -- 3768
					text = ("记忆碎片: " .. tostring(getCollectedCount())) .. " / 7", -- 3768
					y = -6, -- 3768
					alignment = "Center", -- 3768
					opacity = 0.8 -- 3768
				} -- 3768
			) -- 3768
		) -- 3768
	) -- 3768
end -- 3622
Game = function() -- 3797
	local restartLevel, level -- 3797
	local worldRef = useRef(nil) -- 3798
	local debugWorldRef = useRef(nil) -- 3799
	local cameraRef = useRef(nil) -- 3800
	local backgroundRef = useRef(nil) -- 3801
	local shakeTimerRef = useRef(0) -- 3802
	local gameStateRef = useRef("playing") -- 3803
	local stateTimerRef = useRef(0) -- 3804
	local playerCanMoveRef = useRef(true) -- 3805
	local dialogNodeRef = useRef(nil) -- 3806
	local cameraInitRef = useRef(false) -- 3807
	local hasMetNPCRef = useRef(false) -- 3808
	local nearNPCRef = useRef(false) -- 3809
	local promptNodeRef = useRef(nil) -- 3810
	local lastEPressedRef = useRef(false) -- 3811
	local bgmStartedRef = useRef(false) -- 3812
	local secretTargetLevelRef = useRef(nil) -- 3813
	local triggerDeathRef = useRef(false) -- 3814
	if not bgmStartedRef.current then -- 3814
		local levelBGM = getLevelBGM(currentLevel) -- 3818
		playBGM(levelBGM, 0.4) -- 3819
		bgmStartedRef.current = true -- 3820
	end -- 3820
	local function handleDash() -- 3823
		shakeTimerRef.current = SHAKE_DURATION -- 3824
	end -- 3823
	local function handleDeath() -- 3827
		____print("💀 [Game] 玩家死亡动画完成，重生") -- 3828
		restartLevel() -- 3829
	end -- 3827
	local function handleGoal() -- 3832
		____print("🎉 [Game] 玩家到达终点!") -- 3833
		playerCanMoveRef.current = false -- 3834
		local dialog = dialogNodeRef.current -- 3836
		if dialog then -- 3836
			dialog.visible = false -- 3838
			dialog.touchEnabled = false -- 3839
		end -- 3839
		if currentLevel == 6 then -- 3839
			____print("🎬 [Game] 第七关完成，显示假结局") -- 3844
			gameStateRef.current = "transition" -- 3845
			local entry = Director.entry -- 3846
			if entry then -- 3846
				local endingNode = toNode(React.createElement( -- 3848
					ScaledRoot, -- 3849
					nil, -- 3849
					React.createElement( -- 3849
						EndingScene, -- 3850
						{ -- 3850
							dialogType = "fakeEnding", -- 3850
							endingImages = { -- 3850
								"Image/cg/LostEnding-1.png", -- 3853
								"Image/cg/LostEnding-2.png", -- 3853
								"Image/cg/LostEnding-3.png", -- 3853
								"Image/cg/LostEnding-4.png", -- 3853
								"Image/cg/LostEnding-5.png", -- 3854
								"Image/cg/LostEnding-6.png", -- 3854
								"Image/cg/LostEnding-7.png", -- 3854
								"Image/cg/LostEnding-8.png" -- 3854
							}, -- 3854
							onComplete = function() -- 3854
								____print("✅ [Ending] 假结局完成") -- 3857
								unlockedEndings.fake = true -- 3858
								unlockNextLevel(6) -- 3859
								returnToMenu() -- 3860
							end -- 3856
						} -- 3856
					) -- 3856
				)) -- 3856
				entry:addChild(endingNode) -- 3865
			end -- 3865
			return -- 3867
		end -- 3867
		if currentLevel == 7 then -- 3867
			____print("🎬 [Game] 第八关完成，显示结局") -- 3872
			gameStateRef.current = "transition" -- 3873
			local entry = Director.entry -- 3874
			if entry then -- 3874
				local allCollected = isAllCollected() -- 3876
				local collectedCount = getCollectedCount() -- 3877
				____print((("🌟 [Game] 收集品: " .. tostring(collectedCount)) .. "/7, 全部收集: ") .. tostring(allCollected)) -- 3878
				local endingNode = toNode(React.createElement( -- 3880
					ScaledRoot, -- 3881
					nil, -- 3881
					React.createElement( -- 3881
						EndingScene, -- 3882
						{ -- 3882
							dialogType = allCollected and "perfectEnding" or "sacrificeEnding", -- 3882
							endingImages = allCollected and ({ -- 3882
								"Image/cg/TrueEnding-1.png", -- 3886
								"Image/cg/TrueEnding-2.png", -- 3886
								"Image/cg/TrueEnding-3.png", -- 3886
								"Image/cg/TrueEnding-4.png", -- 3886
								"Image/cg/TrueEnding-5.png", -- 3887
								"Image/cg/TrueEnding-6.png", -- 3887
								"Image/cg/TrueEnding-7.png", -- 3887
								"Image/cg/TrueEnding-8.png" -- 3887
							}) or ({ -- 3887
								"Image/cg/SacrificeEnding-1.png", -- 3890
								"Image/cg/SacrificeEnding-2.png", -- 3890
								"Image/cg/SacrificeEnding-3.png", -- 3890
								"Image/cg/SacrificeEnding-4.png", -- 3890
								"Image/cg/SacrificeEnding-5.png", -- 3891
								"Image/cg/SacrificeEnding-6.png", -- 3891
								"Image/cg/SacrificeEnding-7.png", -- 3891
								"Image/cg/SacrificeEnding-8.png" -- 3891
							}), -- 3891
							onComplete = function() -- 3891
								____print("✅ [Ending] 结局完成") -- 3894
								if allCollected then -- 3894
									unlockedEndings.perfect = true -- 3896
								else -- 3896
									unlockedEndings.sacrifice = true -- 3898
								end -- 3898
								saveCollectibles() -- 3900
								returnToMenu() -- 3901
							end -- 3893
						} -- 3893
					) -- 3893
				)) -- 3893
				entry:addChild(endingNode) -- 3906
			end -- 3906
			return -- 3908
		end -- 3908
		____print("⏱️ [Game] 2秒后进入下一关...") -- 3912
		gameStateRef.current = "won" -- 3913
		stateTimerRef.current = 2 -- 3914
	end -- 3832
	local function handleSecretGoal() -- 3917
		local secretGoal = level.secretGoal -- 3918
		if not secretGoal then -- 3918
			return -- 3919
		end -- 3919
		____print("🌟 [Game] 玩家发现隐藏终点！跳转到第 8 关") -- 3921
		gameStateRef.current = "won" -- 3922
		stateTimerRef.current = 1.5 -- 3923
		playerCanMoveRef.current = false -- 3924
		secretTargetLevelRef.current = 7 -- 3925
		local dialog = dialogNodeRef.current -- 3927
		if dialog then -- 3927
			dialog.visible = false -- 3929
			dialog.touchEnabled = false -- 3930
		end -- 3930
	end -- 3917
	local function handleDialogComplete() -- 3934
		____print("✅ [Game] 对话完成,解锁玩家控制") -- 3935
		gameStateRef.current = "playing" -- 3936
		playerCanMoveRef.current = true -- 3937
		local dialog = dialogNodeRef.current -- 3939
		if dialog then -- 3939
			dialog.visible = false -- 3941
			dialog.touchEnabled = false -- 3942
		end -- 3942
	end -- 3934
	restartLevel = function() -- 3946
		____print("🔄 [Game] 重生关卡 " .. tostring(currentLevel + 1)) -- 3947
		local entry = Director.entry -- 3948
		if entry then -- 3948
			entry:removeAllChildren() -- 3950
			entry:addChild(toNode(React.createElement( -- 3951
				ScaledRoot, -- 3952
				nil, -- 3952
				React.createElement(Game, nil) -- 3952
			))) -- 3952
		end -- 3952
	end -- 3946
	local function nextLevel() -- 3959
		____print(("🏆 [Game] 完成第 " .. tostring(currentLevel + 1)) .. " 关") -- 3960
		unlockNextLevel(currentLevel) -- 3961
		if currentLevel + 1 < #LEVELS then -- 3961
			____print(("🎮 [Game] 进入第 " .. tostring(currentLevel + 2)) .. " 关") -- 3964
			startGame(currentLevel + 1) -- 3965
		else -- 3965
			____print("🎊 所有关卡完成!") -- 3967
			returnToMenu() -- 3968
		end -- 3968
	end -- 3959
	local function handleUpdate(deltaTime) -- 3972
		local camera = cameraRef.current -- 3973
		if not camera then -- 3973
			return false -- 3974
		end -- 3974
		if not cameraInitRef.current then -- 3974
			local level = LEVELS[currentLevel + 1] -- 3977
			camera.x = -level.playerStart.x - 150 -- 3978
			camera.y = -level.playerStart.y -- 3979
			cameraInitRef.current = true -- 3980
		end -- 3980
		if Keyboard:isKeyDown("Escape") then -- 3980
			returnToMenu() -- 3984
			return false -- 3985
		end -- 3985
		local targetX = playerPosition.x -- 3988
		local targetY = playerPosition.y -- 3989
		local shakeX = 0 -- 3991
		local shakeY = 0 -- 3992
		if shakeTimerRef.current > 0 then -- 3992
			shakeTimerRef.current = shakeTimerRef.current - deltaTime -- 3995
			local intensity = SHAKE_INTENSITY * (shakeTimerRef.current / SHAKE_DURATION) -- 3996
			shakeX = (math.random() - 0.5) * 2 * intensity -- 3997
			shakeY = (math.random() - 0.5) * 2 * intensity -- 3998
		end -- 3998
		local cameraX = -targetX + shakeX -- 4001
		camera.y = -targetY + shakeY -- 4002
		local level = LEVELS[currentLevel + 1] -- 4005
		if level.cameraLimitX then -- 4005
			cameraX = math.max( -- 4007
				level.cameraLimitX.min, -- 4007
				math.min(level.cameraLimitX.max, cameraX) -- 4007
			) -- 4007
		end -- 4007
		camera.x = cameraX -- 4009
		local background = backgroundRef.current -- 4012
		if background then -- 4012
			local level = LEVELS[currentLevel + 1] -- 4014
			local parallax = level.background.parallax or 0.5 -- 4015
			background.x = -targetX * parallax -- 4016
			background.y = -targetY * parallax -- 4017
		end -- 4017
		if gameStateRef.current == "playing" then -- 4017
			local level = LEVELS[currentLevel + 1] -- 4021
			local npcX = level.npc.x -- 4022
			local npcY = level.npc.y -- 4023
			local dx = playerPosition.x - npcX -- 4024
			local dy = playerPosition.y - npcY -- 4025
			local distance = math.sqrt(dx * dx + dy * dy) -- 4026
			local isNear = distance < 80 -- 4028
			nearNPCRef.current = isNear -- 4029
			local prompt = promptNodeRef.current -- 4031
			if prompt then -- 4031
				prompt.visible = isNear -- 4033
				if isNear then -- 4033
					prompt.x = npcX -- 4035
					prompt.y = npcY + 60 -- 4036
				end -- 4036
			end -- 4036
			local ePressed = Keyboard:isKeyPressed("E") -- 4040
			if isNear and not lastEPressedRef.current and ePressed then -- 4040
				____print("💬 [Game] 按E键触发对话") -- 4042
				gameStateRef.current = "dialog" -- 4043
				playerCanMoveRef.current = false -- 4044
				local dialog = dialogNodeRef.current -- 4046
				if dialog then -- 4046
					dialog.visible = true -- 4048
					dialog.touchEnabled = true -- 4049
				end -- 4049
				if prompt then -- 4049
					prompt.visible = false -- 4053
				end -- 4053
			end -- 4053
			lastEPressedRef.current = ePressed -- 4056
		end -- 4056
		if gameStateRef.current == "won" then -- 4056
			stateTimerRef.current = stateTimerRef.current - deltaTime -- 4060
			if stateTimerRef.current <= 0 then -- 4060
				if secretTargetLevelRef.current ~= nil then -- 4060
					secretTargetLevelRef.current = nil -- 4064
					startGame(7) -- 4065
				else -- 4065
					nextLevel() -- 4067
				end -- 4067
			end -- 4067
		end -- 4067
		return false -- 4072
	end -- 3972
	level = LEVELS[currentLevel + 1] -- 4075
	local ____React_createElement_8 = React.createElement -- 4075
	local ____React_Fragment_7 = React.Fragment -- 4075
	local ____React_createElement_6 = React.createElement -- 4075
	local ____temp_5 = {ref = backgroundRef, order = -100} -- 4075
	local ____level_background_animated_4 -- 4081
	if level.background.animated then -- 4081
		____level_background_animated_4 = React.createElement(AnimatedBackground, { -- 4081
			file = level.background.file, -- 4081
			width = level.background.width, -- 4081
			height = level.background.height, -- 4081
			frameWidth = level.background.frameWidth or level.background.width, -- 4081
			frameHeight = level.background.frameHeight or level.background.height, -- 4081
			frames = level.background.frames or 1, -- 4081
			duration = level.background.duration or 1, -- 4081
			loop = true -- 4081
		}) -- 4081
	else -- 4081
		____level_background_animated_4 = React.createElement("sprite", {file = level.background.file, width = level.background.width, height = level.background.height, filter = "Point"}) -- 4092
	end -- 4092
	return ____React_createElement_8( -- 4077
		____React_Fragment_7, -- 4077
		nil, -- 4077
		____React_createElement_6("node", ____temp_5, ____level_background_animated_4), -- 4077
		React.createElement( -- 4077
			"node", -- 4077
			{ref = cameraRef, onUpdate = handleUpdate}, -- 4077
			React.createElement( -- 4077
				"physics-world", -- 4077
				{ref = worldRef, showDebug = false, gravity = GRAVITY}, -- 4077
				React.createElement(Player, { -- 4077
					x = level.playerStart.x, -- 4077
					y = level.playerStart.y, -- 4077
					worldRef = worldRef, -- 4077
					debugWorldRef = debugWorldRef, -- 4077
					onDash = handleDash, -- 4077
					onDeath = handleDeath, -- 4077
					onGoal = handleGoal, -- 4077
					onSecretGoal = handleSecretGoal, -- 4077
					levelConfig = level, -- 4077
					canMoveRef = playerCanMoveRef, -- 4077
					triggerDeathRef = triggerDeathRef -- 4077
				}), -- 4077
				__TS__ArrayMap( -- 4119
					level.platforms, -- 4119
					function(____, p, i) return React.createElement( -- 4119
						Platform, -- 4120
						{ -- 4120
							key = "p" .. tostring(i), -- 4120
							x = p.x, -- 4120
							y = p.y, -- 4120
							w = p.w, -- 4120
							h = p.h, -- 4120
							file = p.file -- 4120
						} -- 4120
					) end -- 4120
				), -- 4120
				__TS__ArrayMap( -- 4123
					level.hazards, -- 4123
					function(____, h, i) return React.createElement( -- 4123
						Hazard, -- 4124
						{ -- 4124
							key = "h" .. tostring(i), -- 4124
							x = h.x, -- 4124
							y = h.y, -- 4124
							w = h.w, -- 4124
							h = h.h, -- 4124
							file = h.file -- 4124
						} -- 4124
					) end -- 4124
				), -- 4124
				level.movingSpikes and __TS__ArrayMap( -- 4127
					level.movingSpikes, -- 4127
					function(____, spike, i) return React.createElement( -- 4127
						MovingSpike, -- 4128
						{ -- 4128
							key = "ms" .. tostring(i), -- 4128
							startX = spike.startX, -- 4128
							endX = spike.endX, -- 4128
							y = spike.y, -- 4128
							width = spike.width, -- 4128
							height = spike.height, -- 4128
							speed = spike.speed, -- 4128
							delay = spike.delay, -- 4128
							file = spike.file, -- 4128
							onPlayerHit = function() -- 4128
								triggerDeathRef.current = true -- 4139
							end -- 4138
						} -- 4138
					) end -- 4138
				), -- 4138
				React.createElement(Goal, {x = level.goal.x, y = level.goal.y, size = level.goal.size}), -- 4138
				level.secretGoal and React.createElement(SecretGoal, {x = level.secretGoal.x, y = level.secretGoal.y, size = level.secretGoal.size}), -- 4146
				React.createElement(NPC, {x = level.npc.x, y = level.npc.y}), -- 4146
				level.collectible and React.createElement( -- 4152
					Collectible, -- 4153
					{ -- 4153
						x = level.collectible.x, -- 4153
						y = level.collectible.y, -- 4153
						levelIndex = currentLevel, -- 4153
						file = level.collectible.file, -- 4153
						onCollect = function() -- 4153
							____print(("✨ [Game] 收集品已收集！当前进度: " .. tostring(getCollectedCount())) .. "/7") -- 4159
							saveCollectibles() -- 4160
						end -- 4158
					} -- 4158
				), -- 4158
				level.texts and __TS__ArrayMap( -- 4166
					level.texts, -- 4166
					function(____, textConfig, i) return React.createElement( -- 4166
						LevelText, -- 4167
						{ -- 4167
							key = "text" .. tostring(i), -- 4167
							x = textConfig.x, -- 4167
							y = textConfig.y, -- 4167
							text = textConfig.text, -- 4167
							fontSize = textConfig.fontSize, -- 4167
							color = textConfig.color, -- 4167
							showDistance = textConfig.showDistance -- 4167
						} -- 4167
					) end -- 4167
				), -- 4167
				React.createElement( -- 4167
					"node", -- 4167
					{ref = promptNodeRef, visible = false, order = 100}, -- 4167
					React.createElement( -- 4167
						"draw-node", -- 4167
						nil, -- 4167
						React.createElement("rect-shape", { -- 4167
							width = 180, -- 4167
							height = 50, -- 4167
							fillColor = 204, -- 4167
							borderColor = 4294967295, -- 4167
							borderWidth = 2 -- 4167
						}) -- 4167
					), -- 4167
					React.createElement("label", { -- 4167
						fontName = "sarasa-mono-sc-regular", -- 4167
						fontSize = 28, -- 4167
						text = "按 E 对话", -- 4167
						y = -7, -- 4167
						alignment = "Center" -- 4167
					}) -- 4167
				) -- 4167
			), -- 4167
			React.createElement( -- 4167
				"physics-world", -- 4167
				{ -- 4167
					ref = debugWorldRef, -- 4167
					showDebug = true, -- 4167
					gravity = Vec2(0, 0) -- 4167
				} -- 4167
			), -- 4167
			React.createElement( -- 4167
				"node", -- 4167
				{x = -600, y = 400}, -- 4167
				React.createElement("sprite", {width = 200, height = 50, opacity = 0.7}), -- 4167
				"  " -- 4167
			) -- 4167
		), -- 4167
		React.createElement( -- 4167
			"node", -- 4167
			{ref = dialogNodeRef, visible = false, order = 2000}, -- 4167
			React.createElement(SimpleDialog, {messages = level.dialog.start, onComplete = handleDialogComplete, gameStateRef = gameStateRef}) -- 4167
		) -- 4167
	) -- 4167
end -- 3797
local DESIGN_WIDTH = 1500 -- 4224
local DESIGN_HEIGHT = 720 -- 4225
local function calculateScale() -- 4228
	local actualWidth = View.size.width -- 4229
	local actualHeight = View.size.height -- 4230
	local scaleX = actualWidth / DESIGN_WIDTH -- 4231
	local scaleY = actualHeight / DESIGN_HEIGHT -- 4232
	local scale = math.min(scaleX, scaleY) -- 4233
	return math.min(scale, 1) -- 4234
end -- 4228
local globalScale = calculateScale() -- 4238
local lastWindowWidth = View.size.width -- 4241
local lastWindowHeight = View.size.height -- 4242
____print((("📺 [窗口] 设计分辨率: " .. tostring(DESIGN_WIDTH)) .. "x") .. tostring(DESIGN_HEIGHT)) -- 4244
____print((("📺 [窗口] 实际窗口: " .. tostring(lastWindowWidth)) .. "x") .. tostring(lastWindowHeight)) -- 4245
____print("📺 [窗口] 缩放比例: " .. __TS__NumberToFixed(globalScale, 2)) -- 4246
ScaledRoot = function(props) -- 4249
	local nodeRef = useRef(nil) -- 4250
	local function handleUpdate(deltaTime) -- 4252
		local currentWidth = View.size.width -- 4253
		local currentHeight = View.size.height -- 4254
		if currentWidth ~= lastWindowWidth or currentHeight ~= lastWindowHeight then -- 4254
			lastWindowWidth = currentWidth -- 4258
			lastWindowHeight = currentHeight -- 4259
			globalScale = calculateScale() -- 4260
			local node = nodeRef.current -- 4263
			if node then -- 4263
				node.scaleX = globalScale -- 4265
				node.scaleY = globalScale -- 4266
			end -- 4266
			____print((((("📺 [窗口] 尺寸改变: " .. tostring(currentWidth)) .. "x") .. tostring(currentHeight)) .. ", 缩放: ") .. __TS__NumberToFixed(globalScale, 2)) -- 4269
		end -- 4269
		return false -- 4272
	end -- 4252
	return React.createElement("node", {ref = nodeRef, scaleX = globalScale, scaleY = globalScale, onUpdate = handleUpdate}, props.children) -- 4275
end -- 4249
loadSave() -- 4283
toNode(React.createElement( -- 4284
	ScaledRoot, -- 4285
	nil, -- 4285
	React.createElement(MainMenu, nil) -- 4285
)) -- 4285
return ____exports -- 4285